[WIN32SS] Cleanup fonts at process destruction + implement font memory reference...
[reactos.git] / reactos / win32ss / gdi / ntgdi / freetype.c
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 static const UNICODE_STRING SystemW = RTL_CONSTANT_STRING(L"System");
55 static const UNICODE_STRING FixedSysW = RTL_CONSTANT_STRING(L"FixedSys");
56
57 /* registry */
58 static UNICODE_STRING FontRegPath =
59 RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
60
61
62 /* The FreeType library is not thread safe, so we have
63 to serialize access to it */
64 static PFAST_MUTEX FreeTypeLock;
65
66 static LIST_ENTRY FontListHead;
67 static PFAST_MUTEX FontListLock;
68 static BOOL RenderingEnabled = TRUE;
69
70 #define IntLockGlobalFonts \
71 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FontListLock)
72
73 #define IntUnLockGlobalFonts \
74 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
75
76 #define ASSERT_GLOBALFONTS_LOCK_HELD() \
77 ASSERT(FreeTypeLock->Owner == KeGetCurrentThread())
78
79 #define IntLockFreeType \
80 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
81
82 #define IntUnLockFreeType \
83 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock)
84
85 #define ASSERT_FREETYPE_LOCK_HELD() \
86 ASSERT(FreeTypeLock->Owner == KeGetCurrentThread())
87
88 #define MAX_FONT_CACHE 256
89
90 static LIST_ENTRY FontCacheListHead;
91 static UINT FontCacheNumEntries;
92
93 static PWCHAR ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */
94 {
95 L"Western", /* 00 */
96 L"Central_European",
97 L"Cyrillic",
98 L"Greek",
99 L"Turkish",
100 L"Hebrew",
101 L"Arabic",
102 L"Baltic",
103 L"Vietnamese", /* 08 */
104 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */
105 L"Thai",
106 L"Japanese",
107 L"CHINESE_GB2312",
108 L"Hangul",
109 L"CHINESE_BIG5",
110 L"Hangul(Johab)",
111 NULL, NULL, /* 23 */
112 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
113 L"Symbol" /* 31 */
114 };
115
116 /*
117 * For TranslateCharsetInfo
118 */
119 #define CP_SYMBOL 42
120 #define MAXTCIINDEX 32
121 static const CHARSETINFO FontTci[MAXTCIINDEX] =
122 {
123 /* ANSI */
124 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
125 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
126 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
127 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
128 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
129 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
130 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
131 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
132 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
133 /* reserved by ANSI */
134 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
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 /* ANSI and OEM */
142 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
143 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
144 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
145 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
146 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
147 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
148 /* Reserved for alternate ANSI and OEM */
149 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
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 /* Reserved for system */
158 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
159 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
160 };
161
162 /* list head */
163 static RTL_STATIC_LIST_HEAD(FontSubstListHead);
164
165 static void
166 SharedMem_AddRef(PSHARED_MEM Ptr)
167 {
168 ASSERT_FREETYPE_LOCK_HELD();
169
170 ++Ptr->RefCount;
171 }
172
173 static PSHARED_FACE
174 SharedFace_Create(FT_Face Face, PSHARED_MEM Memory)
175 {
176 PSHARED_FACE Ptr;
177 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
178 if (Ptr)
179 {
180 Ptr->Face = Face;
181 Ptr->RefCount = 1;
182 Ptr->Memory = Memory;
183 SharedMem_AddRef(Memory);
184 DPRINT("Creating SharedFace for %s\n", Face->family_name);
185 }
186 return Ptr;
187 }
188
189 static PSHARED_MEM
190 SharedMem_Create(PBYTE Buffer, ULONG BufferSize, BOOL IsMapping)
191 {
192 PSHARED_MEM Ptr;
193 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_MEM), TAG_FONT);
194 if (Ptr)
195 {
196 Ptr->Buffer = Buffer;
197 Ptr->BufferSize = BufferSize;
198 Ptr->RefCount = 1;
199 Ptr->IsMapping = IsMapping;
200 DPRINT("Creating SharedMem for %p (%i, %p)\n", Buffer, IsMapping, Ptr);
201 }
202 return Ptr;
203 }
204
205 static void
206 SharedFace_AddRef(PSHARED_FACE Ptr)
207 {
208 ASSERT_FREETYPE_LOCK_HELD();
209
210 ++Ptr->RefCount;
211 }
212
213 static void
214 RemoveCachedEntry(PFONT_CACHE_ENTRY Entry)
215 {
216 ASSERT_FREETYPE_LOCK_HELD();
217
218 FT_Done_Glyph((FT_Glyph)Entry->BitmapGlyph);
219 RemoveEntryList(&Entry->ListEntry);
220 ExFreePoolWithTag(Entry, TAG_FONT);
221 FontCacheNumEntries--;
222 ASSERT(FontCacheNumEntries <= MAX_FONT_CACHE);
223 }
224
225 static void
226 RemoveCacheEntries(FT_Face Face)
227 {
228 PLIST_ENTRY CurrentEntry;
229 PFONT_CACHE_ENTRY FontEntry;
230
231 ASSERT_FREETYPE_LOCK_HELD();
232
233 CurrentEntry = FontCacheListHead.Flink;
234 while (CurrentEntry != &FontCacheListHead)
235 {
236 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
237 CurrentEntry = CurrentEntry->Flink;
238
239 if (FontEntry->Face == Face)
240 {
241 RemoveCachedEntry(FontEntry);
242 }
243 }
244 }
245
246 static void SharedMem_Release(PSHARED_MEM Ptr)
247 {
248 ASSERT_FREETYPE_LOCK_HELD();
249 ASSERT(Ptr->RefCount > 0);
250
251 if (Ptr->RefCount <= 0)
252 return;
253
254 --Ptr->RefCount;
255 if (Ptr->RefCount == 0)
256 {
257 DPRINT("Releasing SharedMem for %p (%i, %p)\n", Ptr->Buffer, Ptr->IsMapping, Ptr);
258 if (Ptr->IsMapping)
259 MmUnmapViewInSystemSpace(Ptr->Buffer);
260 else
261 ExFreePoolWithTag(Ptr->Buffer, TAG_FONT);
262 ExFreePoolWithTag(Ptr, TAG_FONT);
263 }
264 }
265
266 static void
267 SharedFace_Release(PSHARED_FACE Ptr)
268 {
269 IntLockFreeType;
270 ASSERT(Ptr->RefCount > 0);
271
272 if (Ptr->RefCount <= 0)
273 return;
274
275 --Ptr->RefCount;
276 if (Ptr->RefCount == 0)
277 {
278 DPRINT("Releasing SharedFace for %s\n", Ptr->Face->family_name);
279 RemoveCacheEntries(Ptr->Face);
280 FT_Done_Face(Ptr->Face);
281 SharedMem_Release(Ptr->Memory);
282 ExFreePoolWithTag(Ptr, TAG_FONT);
283 }
284 IntUnLockFreeType;
285 }
286
287
288 /*
289 * IntLoadFontSubstList --- loads the list of font substitutes
290 */
291 BOOL FASTCALL
292 IntLoadFontSubstList(PLIST_ENTRY pHead)
293 {
294 NTSTATUS Status;
295 HANDLE KeyHandle;
296 OBJECT_ATTRIBUTES ObjectAttributes;
297 KEY_FULL_INFORMATION KeyFullInfo;
298 ULONG i, Length;
299 UNICODE_STRING FromW, ToW;
300 BYTE InfoBuffer[128];
301 PKEY_VALUE_FULL_INFORMATION pInfo;
302 BYTE CharSets[FONTSUBST_FROM_AND_TO];
303 LPWSTR pch;
304 PFONTSUBST_ENTRY pEntry;
305
306 /* the FontSubstitutes registry key */
307 static UNICODE_STRING FontSubstKey =
308 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\"
309 L"Microsoft\\Windows NT\\CurrentVersion\\"
310 L"FontSubstitutes");
311
312 /* open registry key */
313 InitializeObjectAttributes(&ObjectAttributes, &FontSubstKey,
314 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
315 NULL, NULL);
316 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
317 if (!NT_SUCCESS(Status))
318 {
319 DPRINT("ZwOpenKey failed: 0x%08X\n", Status);
320 return FALSE; /* failure */
321 }
322
323 /* query count of values */
324 Status = ZwQueryKey(KeyHandle, KeyFullInformation,
325 &KeyFullInfo, sizeof(KeyFullInfo), &Length);
326 if (!NT_SUCCESS(Status))
327 {
328 DPRINT("ZwQueryKey failed: 0x%08X\n", Status);
329 ZwClose(KeyHandle);
330 return FALSE; /* failure */
331 }
332
333 /* for each value */
334 for (i = 0; i < KeyFullInfo.Values; ++i)
335 {
336 /* get value name */
337 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
338 InfoBuffer, sizeof(InfoBuffer), &Length);
339 if (!NT_SUCCESS(Status))
340 {
341 DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status);
342 break; /* failure */
343 }
344
345 /* create FromW string */
346 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
347 Length = pInfo->NameLength / sizeof(WCHAR);
348 pInfo->Name[Length] = UNICODE_NULL; /* truncate */
349 Status = RtlCreateUnicodeString(&FromW, pInfo->Name);
350 if (!NT_SUCCESS(Status))
351 {
352 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
353 break; /* failure */
354 }
355
356 /* query value */
357 Status = ZwQueryValueKey(KeyHandle, &FromW, KeyValueFullInformation,
358 InfoBuffer, sizeof(InfoBuffer), &Length);
359 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
360 if (!NT_SUCCESS(Status) || !pInfo->DataLength)
361 {
362 DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status);
363 RtlFreeUnicodeString(&FromW);
364 break; /* failure */
365 }
366
367 /* create ToW string */
368 pch = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
369 Length = pInfo->DataLength / sizeof(WCHAR);
370 pch[Length] = UNICODE_NULL; /* truncate */
371 Status = RtlCreateUnicodeString(&ToW, pch);
372 if (!NT_SUCCESS(Status))
373 {
374 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
375 RtlFreeUnicodeString(&FromW);
376 break; /* failure */
377 }
378
379 /* does charset exist? (from) */
380 CharSets[FONTSUBST_FROM] = DEFAULT_CHARSET;
381 pch = wcsrchr(FromW.Buffer, L',');
382 if (pch)
383 {
384 /* truncate */
385 *pch = UNICODE_NULL;
386 FromW.Length = (pch - FromW.Buffer) * sizeof(WCHAR);
387 /* parse charset number */
388 CharSets[FONTSUBST_FROM] = (BYTE)_wtoi(pch + 1);
389 }
390
391 /* does charset exist? (to) */
392 CharSets[FONTSUBST_TO] = DEFAULT_CHARSET;
393 pch = wcsrchr(ToW.Buffer, L',');
394 if (pch)
395 {
396 /* truncate */
397 *pch = UNICODE_NULL;
398 ToW.Length = (pch - ToW.Buffer) * sizeof(WCHAR);
399 /* parse charset number */
400 CharSets[FONTSUBST_TO] = (BYTE)_wtoi(pch + 1);
401 }
402
403 /* allocate an entry */
404 pEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONTSUBST_ENTRY), TAG_FONT);
405 if (pEntry == NULL)
406 {
407 DPRINT("ExAllocatePoolWithTag failed\n");
408 RtlFreeUnicodeString(&FromW);
409 RtlFreeUnicodeString(&ToW);
410 break; /* failure */
411 }
412
413 /* store to *pEntry */
414 pEntry->FontNames[FONTSUBST_FROM] = FromW;
415 pEntry->FontNames[FONTSUBST_TO] = ToW;
416 pEntry->CharSets[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
417 pEntry->CharSets[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
418
419 /* insert pEntry to *pHead */
420 InsertTailList(pHead, &pEntry->ListEntry);
421 }
422
423 /* close now */
424 ZwClose(KeyHandle);
425
426 return NT_SUCCESS(Status);
427 }
428
429 BOOL FASTCALL
430 InitFontSupport(VOID)
431 {
432 ULONG ulError;
433
434 InitializeListHead(&FontListHead);
435 InitializeListHead(&FontCacheListHead);
436 FontCacheNumEntries = 0;
437 /* Fast Mutexes must be allocated from non paged pool */
438 FontListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
439 if (FontListLock == NULL)
440 {
441 return FALSE;
442 }
443
444 ExInitializeFastMutex(FontListLock);
445 FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
446 if (FreeTypeLock == NULL)
447 {
448 return FALSE;
449 }
450 ExInitializeFastMutex(FreeTypeLock);
451
452 ulError = FT_Init_FreeType(&library);
453 if (ulError)
454 {
455 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
456 return FALSE;
457 }
458
459 IntLoadSystemFonts();
460 IntLoadFontSubstList(&FontSubstListHead);
461
462 return TRUE;
463 }
464
465 VOID
466 FtSetCoordinateTransform(
467 FT_Face face,
468 PMATRIX pmx)
469 {
470 FT_Matrix ftmatrix;
471 FLOATOBJ efTemp;
472
473 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
474 efTemp = pmx->efM11;
475 FLOATOBJ_MulLong(&efTemp, 0x00010000);
476 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
477
478 efTemp = pmx->efM12;
479 FLOATOBJ_MulLong(&efTemp, 0x00010000);
480 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
481
482 efTemp = pmx->efM21;
483 FLOATOBJ_MulLong(&efTemp, 0x00010000);
484 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
485
486 efTemp = pmx->efM22;
487 FLOATOBJ_MulLong(&efTemp, 0x00010000);
488 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
489
490 /* Set the transformation matrix */
491 FT_Set_Transform(face, &ftmatrix, 0);
492 }
493
494 static BOOL
495 SubstituteFontByList(PLIST_ENTRY pHead,
496 PUNICODE_STRING pOutputName,
497 PUNICODE_STRING pInputName,
498 BYTE RequestedCharSet,
499 BYTE CharSetMap[FONTSUBST_FROM_AND_TO])
500 {
501 NTSTATUS Status;
502 PLIST_ENTRY pListEntry;
503 PFONTSUBST_ENTRY pSubstEntry;
504 BYTE CharSets[FONTSUBST_FROM_AND_TO];
505
506 CharSetMap[FONTSUBST_FROM] = DEFAULT_CHARSET;
507 CharSetMap[FONTSUBST_TO] = RequestedCharSet;
508
509 /* for each list entry */
510 for (pListEntry = pHead->Flink;
511 pListEntry != pHead;
512 pListEntry = pListEntry->Flink)
513 {
514 pSubstEntry =
515 (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_ENTRY, ListEntry);
516
517 CharSets[FONTSUBST_FROM] = pSubstEntry->CharSets[FONTSUBST_FROM];
518
519 if (CharSets[FONTSUBST_FROM] != DEFAULT_CHARSET &&
520 CharSets[FONTSUBST_FROM] != RequestedCharSet)
521 {
522 continue; /* not matched */
523 }
524
525 /* does charset number exist? (to) */
526 if (pSubstEntry->CharSets[FONTSUBST_TO] != DEFAULT_CHARSET)
527 {
528 CharSets[FONTSUBST_TO] = pSubstEntry->CharSets[FONTSUBST_TO];
529 }
530 else
531 {
532 CharSets[FONTSUBST_TO] = RequestedCharSet;
533 }
534
535 /* does font name match? */
536 if (!RtlEqualUnicodeString(&pSubstEntry->FontNames[FONTSUBST_FROM],
537 pInputName, TRUE))
538 {
539 continue; /* not matched */
540 }
541
542 /* update *pOutputName */
543 RtlFreeUnicodeString(pOutputName);
544 Status = RtlCreateUnicodeString(pOutputName,
545 pSubstEntry->FontNames[FONTSUBST_TO].Buffer);
546 if (!NT_SUCCESS(Status))
547 {
548 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
549 continue; /* cannot create string */
550 }
551
552 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
553 {
554 /* update CharSetMap */
555 CharSetMap[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
556 CharSetMap[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
557 }
558 return TRUE; /* success */
559 }
560
561 return FALSE;
562 }
563
564 static BOOL
565 SubstituteFontRecurse(PUNICODE_STRING pInOutName, BYTE *pRequestedCharSet)
566 {
567 UINT RecurseCount = 5;
568 UNICODE_STRING OutputNameW = { 0 };
569 BYTE CharSetMap[FONTSUBST_FROM_AND_TO];
570 BOOL Found;
571
572 if (pInOutName->Buffer[0] == UNICODE_NULL)
573 return FALSE;
574
575 while (RecurseCount-- > 0)
576 {
577 RtlInitUnicodeString(&OutputNameW, NULL);
578 Found = SubstituteFontByList(&FontSubstListHead,
579 &OutputNameW, pInOutName,
580 *pRequestedCharSet, CharSetMap);
581 if (!Found)
582 break;
583
584 /* update *pInOutName and *pRequestedCharSet */
585 RtlFreeUnicodeString(pInOutName);
586 *pInOutName = OutputNameW;
587 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
588 CharSetMap[FONTSUBST_FROM] == *pRequestedCharSet)
589 {
590 *pRequestedCharSet = CharSetMap[FONTSUBST_TO];
591 }
592 }
593
594 return TRUE; /* success */
595 }
596
597 /*
598 * IntLoadSystemFonts
599 *
600 * Search the system font directory and adds each font found.
601 */
602 VOID FASTCALL
603 IntLoadSystemFonts(VOID)
604 {
605 OBJECT_ATTRIBUTES ObjectAttributes;
606 UNICODE_STRING Directory, FileName, TempString;
607 IO_STATUS_BLOCK Iosb;
608 HANDLE hDirectory;
609 BYTE *DirInfoBuffer;
610 PFILE_DIRECTORY_INFORMATION DirInfo;
611 BOOLEAN bRestartScan = TRUE;
612 NTSTATUS Status;
613 INT i;
614 static UNICODE_STRING SearchPatterns[] =
615 {
616 RTL_CONSTANT_STRING(L"*.ttf"),
617 RTL_CONSTANT_STRING(L"*.ttc"),
618 RTL_CONSTANT_STRING(L"*.otf"),
619 RTL_CONSTANT_STRING(L"*.otc"),
620 RTL_CONSTANT_STRING(L"*.fon"),
621 RTL_CONSTANT_STRING(L"*.fnt")
622 };
623
624 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
625
626 InitializeObjectAttributes(
627 &ObjectAttributes,
628 &Directory,
629 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
630 NULL,
631 NULL);
632
633 Status = ZwOpenFile(
634 &hDirectory,
635 SYNCHRONIZE | FILE_LIST_DIRECTORY,
636 &ObjectAttributes,
637 &Iosb,
638 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
639 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
640
641 if (NT_SUCCESS(Status))
642 {
643 for (i = 0; i < _countof(SearchPatterns); ++i)
644 {
645 DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
646 if (DirInfoBuffer == NULL)
647 {
648 ZwClose(hDirectory);
649 return;
650 }
651
652 FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
653 if (FileName.Buffer == NULL)
654 {
655 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
656 ZwClose(hDirectory);
657 return;
658 }
659 FileName.Length = 0;
660 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
661
662 while (1)
663 {
664 Status = ZwQueryDirectoryFile(
665 hDirectory,
666 NULL,
667 NULL,
668 NULL,
669 &Iosb,
670 DirInfoBuffer,
671 0x4000,
672 FileDirectoryInformation,
673 FALSE,
674 &SearchPatterns[i],
675 bRestartScan);
676
677 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
678 {
679 break;
680 }
681
682 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
683 while (1)
684 {
685 TempString.Buffer = DirInfo->FileName;
686 TempString.Length =
687 TempString.MaximumLength = DirInfo->FileNameLength;
688 RtlCopyUnicodeString(&FileName, &Directory);
689 RtlAppendUnicodeStringToString(&FileName, &TempString);
690 IntGdiAddFontResource(&FileName, 0);
691 if (DirInfo->NextEntryOffset == 0)
692 break;
693 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
694 }
695
696 bRestartScan = FALSE;
697 }
698
699 ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
700 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
701 }
702 ZwClose(hDirectory);
703 }
704 }
705
706 static BYTE
707 ItalicFromStyle(const char *style_name)
708 {
709 if (style_name == NULL || style_name[0] == 0)
710 return FALSE;
711 if (strstr(style_name, "Italic") != NULL)
712 return TRUE;
713 if (strstr(style_name, "Oblique") != NULL)
714 return TRUE;
715 return FALSE;
716 }
717
718 static LONG
719 WeightFromStyle(const char *style_name)
720 {
721 if (style_name == NULL || style_name[0] == 0)
722 return FW_NORMAL;
723 if (strstr(style_name, "Regular") != NULL)
724 return FW_REGULAR;
725 if (strstr(style_name, "Normal") != NULL)
726 return FW_NORMAL;
727 if (strstr(style_name, "SemiBold") != NULL)
728 return FW_SEMIBOLD;
729 if (strstr(style_name, "UltraBold") != NULL)
730 return FW_ULTRABOLD;
731 if (strstr(style_name, "DemiBold") != NULL)
732 return FW_DEMIBOLD;
733 if (strstr(style_name, "ExtraBold") != NULL)
734 return FW_EXTRABOLD;
735 if (strstr(style_name, "Bold") != NULL)
736 return FW_BOLD;
737 if (strstr(style_name, "UltraLight") != NULL)
738 return FW_ULTRALIGHT;
739 if (strstr(style_name, "ExtraLight") != NULL)
740 return FW_EXTRALIGHT;
741 if (strstr(style_name, "Light") != NULL)
742 return FW_LIGHT;
743 if (strstr(style_name, "Hairline") != NULL)
744 return 50;
745 if (strstr(style_name, "Book") != NULL)
746 return 350;
747 if (strstr(style_name, "ExtraBlack") != NULL)
748 return 950;
749 if (strstr(style_name, "UltraBlack") != NULL)
750 return 1000;
751 if (strstr(style_name, "Black") != NULL)
752 return FW_BLACK;
753 if (strstr(style_name, "Medium") != NULL)
754 return FW_MEDIUM;
755 if (strstr(style_name, "Thin") != NULL)
756 return FW_THIN;
757 if (strstr(style_name, "Heavy") != NULL)
758 return FW_HEAVY;
759 return FW_NORMAL;
760 }
761
762 static INT FASTCALL
763 IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
764 PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
765 {
766 FT_Error Error;
767 PFONT_ENTRY Entry;
768 FONT_ENTRY_MEM* PrivateEntry = NULL;
769 FONTGDI * FontGDI;
770 NTSTATUS Status;
771 FT_Face Face;
772 ANSI_STRING AnsiFaceName;
773 FT_WinFNT_HeaderRec WinFNT;
774 INT FontCount = 0, CharSetCount = 0;
775 PUNICODE_STRING pFileName = pLoadFont->pFileName;
776 DWORD Characteristics = pLoadFont->Characteristics;
777 PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
778 TT_OS2 * pOS2;
779 INT BitIndex;
780 FT_UShort os2_version;
781 FT_ULong os2_ulCodePageRange1;
782 FT_UShort os2_usWeightClass;
783
784 if (SharedFace == NULL && CharSetIndex == -1)
785 {
786 /* load a face from memory */
787 IntLockFreeType;
788 Error = FT_New_Memory_Face(
789 library,
790 pLoadFont->Memory->Buffer,
791 pLoadFont->Memory->BufferSize,
792 ((FontIndex != -1) ? FontIndex : 0),
793 &Face);
794
795 if (!Error)
796 SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
797
798 IntUnLockFreeType;
799
800 if (FT_IS_SFNT(Face))
801 pLoadFont->IsTrueType = TRUE;
802
803 if (Error || SharedFace == NULL)
804 {
805 if (SharedFace)
806 SharedFace_Release(SharedFace);
807
808 if (Error == FT_Err_Unknown_File_Format)
809 DPRINT1("Unknown font file format\n");
810 else
811 DPRINT1("Error reading font (error code: %d)\n", Error);
812 return 0; /* failure */
813 }
814 }
815 else
816 {
817 Face = SharedFace->Face;
818 IntLockFreeType;
819 SharedFace_AddRef(SharedFace);
820 IntUnLockFreeType;
821 }
822
823 /* allocate a FONT_ENTRY */
824 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
825 if (!Entry)
826 {
827 SharedFace_Release(SharedFace);
828 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
829 return 0; /* failure */
830 }
831
832 /* allocate a FONTGDI */
833 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
834 if (!FontGDI)
835 {
836 SharedFace_Release(SharedFace);
837 ExFreePoolWithTag(Entry, TAG_FONT);
838 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
839 return 0; /* failure */
840 }
841
842 /* set file name */
843 if (pFileName)
844 {
845 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool,
846 pFileName->Length + sizeof(UNICODE_NULL),
847 GDITAG_PFF);
848 if (FontGDI->Filename == NULL)
849 {
850 EngFreeMem(FontGDI);
851 SharedFace_Release(SharedFace);
852 ExFreePoolWithTag(Entry, TAG_FONT);
853 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
854 return 0; /* failure */
855 }
856 RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
857 FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
858 }
859 else
860 {
861 FontGDI->Filename = NULL;
862
863 PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT);
864 if (!PrivateEntry)
865 {
866 if (FontGDI->Filename)
867 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
868 EngFreeMem(FontGDI);
869 SharedFace_Release(SharedFace);
870 ExFreePoolWithTag(Entry, TAG_FONT);
871 return 0;
872 }
873
874 PrivateEntry->Entry = Entry;
875 if (pLoadFont->PrivateEntry)
876 {
877 InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry);
878 }
879 else
880 {
881 InitializeListHead(&PrivateEntry->ListEntry);
882 pLoadFont->PrivateEntry = PrivateEntry;
883 }
884 }
885
886 /* set face */
887 FontGDI->SharedFace = SharedFace;
888 FontGDI->CharSet = ANSI_CHARSET;
889 FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name);
890 FontGDI->RequestItalic = FALSE;
891 FontGDI->OriginalWeight = WeightFromStyle(Face->style_name);
892 FontGDI->RequestWeight = FW_NORMAL;
893
894 RtlInitAnsiString(&AnsiFaceName, Face->family_name);
895 Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
896 if (!NT_SUCCESS(Status))
897 {
898 if (PrivateEntry)
899 {
900 if (pLoadFont->PrivateEntry == PrivateEntry)
901 {
902 pLoadFont->PrivateEntry = NULL;
903 }
904 else
905 {
906 RemoveEntryList(&PrivateEntry->ListEntry);
907 }
908 ExFreePoolWithTag(PrivateEntry, TAG_FONT);
909 }
910 if (FontGDI->Filename)
911 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
912 EngFreeMem(FontGDI);
913 SharedFace_Release(SharedFace);
914 ExFreePoolWithTag(Entry, TAG_FONT);
915 return 0;
916 }
917
918 os2_version = 0;
919 IntLockFreeType;
920 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
921 if (pOS2)
922 {
923 os2_version = pOS2->version;
924 os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
925 os2_usWeightClass = pOS2->usWeightClass;
926 }
927 IntUnLockFreeType;
928
929 if (pOS2 && os2_version >= 1)
930 {
931 /* get charset and weight from OS/2 header */
932
933 /* Make sure we do not use this pointer anymore */
934 pOS2 = NULL;
935
936 for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
937 {
938 if (os2_ulCodePageRange1 & (1 << BitIndex))
939 {
940 if (FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
941 continue;
942
943 if ((CharSetIndex == -1 && CharSetCount == 0) ||
944 CharSetIndex == CharSetCount)
945 {
946 FontGDI->CharSet = FontTci[BitIndex].ciCharset;
947 }
948
949 ++CharSetCount;
950 }
951 }
952
953 /* set actual weight */
954 FontGDI->OriginalWeight = os2_usWeightClass;
955 }
956 else
957 {
958 /* get charset from WinFNT header */
959 IntLockFreeType;
960 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
961 if (!Error)
962 {
963 FontGDI->CharSet = WinFNT.charset;
964 }
965 IntUnLockFreeType;
966 }
967
968 /* FIXME: CharSet is invalid on Marlett */
969 if (RtlEqualUnicodeString(&Entry->FaceName, &MarlettW, TRUE))
970 {
971 FontGDI->CharSet = SYMBOL_CHARSET;
972 }
973
974 ++FontCount;
975 DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
976 DPRINT("Num glyphs: %d\n", Face->num_glyphs);
977 DPRINT("CharSet: %d\n", FontGDI->CharSet);
978
979 /* Add this font resource to the font table */
980 Entry->Font = FontGDI;
981 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
982
983 if (Characteristics & FR_PRIVATE)
984 {
985 /* private font */
986 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
987 IntLockProcessPrivateFonts(Win32Process);
988 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
989 IntUnLockProcessPrivateFonts(Win32Process);
990 }
991 else
992 {
993 /* global font */
994 IntLockGlobalFonts;
995 InsertTailList(&FontListHead, &Entry->ListEntry);
996 IntUnLockGlobalFonts;
997 }
998
999 if (FontIndex == -1)
1000 {
1001 if (FT_IS_SFNT(Face))
1002 {
1003 TT_Face TrueType = (TT_Face)Face;
1004 if (TrueType->ttc_header.count > 1)
1005 {
1006 FT_Long i;
1007 for (i = 1; i < TrueType->ttc_header.count; ++i)
1008 {
1009 FontCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
1010 }
1011 }
1012 }
1013 FontIndex = 0;
1014 }
1015
1016 if (CharSetIndex == -1)
1017 {
1018 INT i;
1019
1020 if (pLoadFont->RegValueName.Length == 0)
1021 {
1022 RtlCreateUnicodeString(pValueName, Entry->FaceName.Buffer);
1023 }
1024 else
1025 {
1026 UNICODE_STRING NewString;
1027 USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + Entry->FaceName.Length;
1028 NewString.Length = 0;
1029 NewString.MaximumLength = Length + sizeof(WCHAR);
1030 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1031 NewString.MaximumLength,
1032 TAG_USTR);
1033 NewString.Buffer[0] = UNICODE_NULL;
1034
1035 RtlAppendUnicodeStringToString(&NewString, pValueName);
1036 RtlAppendUnicodeToString(&NewString, L" & ");
1037 RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
1038
1039 RtlFreeUnicodeString(pValueName);
1040 *pValueName = NewString;
1041 }
1042
1043 for (i = 1; i < CharSetCount; ++i)
1044 {
1045 FontCount += IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
1046 }
1047 }
1048
1049 return FontCount; /* number of loaded fonts */
1050 }
1051
1052 /*
1053 * IntGdiAddFontResource
1054 *
1055 * Adds the font resource from the specified file to the system.
1056 */
1057
1058 INT FASTCALL
1059 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
1060 {
1061 NTSTATUS Status;
1062 HANDLE FileHandle;
1063 PVOID Buffer = NULL;
1064 IO_STATUS_BLOCK Iosb;
1065 PVOID SectionObject;
1066 ULONG ViewSize = 0;
1067 LARGE_INTEGER SectionSize;
1068 OBJECT_ATTRIBUTES ObjectAttributes;
1069 GDI_LOAD_FONT LoadFont;
1070 INT FontCount;
1071 HANDLE KeyHandle;
1072 static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
1073
1074 /* Open the font file */
1075 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
1076 Status = ZwOpenFile(
1077 &FileHandle,
1078 FILE_GENERIC_READ | SYNCHRONIZE,
1079 &ObjectAttributes,
1080 &Iosb,
1081 FILE_SHARE_READ,
1082 FILE_SYNCHRONOUS_IO_NONALERT);
1083 if (!NT_SUCCESS(Status))
1084 {
1085 DPRINT("Could not load font file: %wZ\n", FileName);
1086 return 0;
1087 }
1088
1089 SectionSize.QuadPart = 0LL;
1090 Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
1091 NULL, &SectionSize, PAGE_READONLY,
1092 SEC_COMMIT, FileHandle, NULL);
1093 if (!NT_SUCCESS(Status))
1094 {
1095 DPRINT("Could not map file: %wZ\n", FileName);
1096 ZwClose(FileHandle);
1097 return 0;
1098 }
1099 ZwClose(FileHandle);
1100
1101 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
1102 if (!NT_SUCCESS(Status))
1103 {
1104 DPRINT("Could not map file: %wZ\n", FileName);
1105 ObDereferenceObject(SectionObject);
1106 return 0;
1107 }
1108
1109 LoadFont.pFileName = FileName;
1110 LoadFont.Memory = SharedMem_Create(Buffer, ViewSize, TRUE);
1111 LoadFont.Characteristics = Characteristics;
1112 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1113 LoadFont.IsTrueType = FALSE;
1114 LoadFont.PrivateEntry = NULL;
1115 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1116
1117 ObDereferenceObject(SectionObject);
1118
1119 /* Release our copy */
1120 IntLockFreeType;
1121 SharedMem_Release(LoadFont.Memory);
1122 IntUnLockFreeType;
1123
1124 if (FontCount > 0)
1125 {
1126 if (LoadFont.IsTrueType)
1127 {
1128 /* append " (TrueType)" */
1129 UNICODE_STRING NewString;
1130 USHORT Length;
1131
1132 Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length;
1133 NewString.Length = 0;
1134 NewString.MaximumLength = Length + sizeof(WCHAR);
1135 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1136 NewString.MaximumLength,
1137 TAG_USTR);
1138 NewString.Buffer[0] = UNICODE_NULL;
1139
1140 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
1141 RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
1142 RtlFreeUnicodeString(&LoadFont.RegValueName);
1143 LoadFont.RegValueName = NewString;
1144 }
1145
1146 /* registry */
1147 InitializeObjectAttributes(&ObjectAttributes, &FontRegPath,
1148 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1149 NULL, NULL);
1150 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
1151 if (NT_SUCCESS(Status))
1152 {
1153 ULONG DataSize;
1154 LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
1155 if (pFileName)
1156 {
1157 pFileName++;
1158 DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
1159 ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
1160 pFileName, DataSize);
1161 }
1162 ZwClose(KeyHandle);
1163 }
1164 }
1165 RtlFreeUnicodeString(&LoadFont.RegValueName);
1166
1167 return FontCount;
1168 }
1169
1170 HANDLE FASTCALL
1171 IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
1172 {
1173 GDI_LOAD_FONT LoadFont;
1174 FONT_ENTRY_COLL_MEM* EntryCollection;
1175 INT FontCount;
1176 HANDLE Ret = 0;
1177
1178 PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
1179
1180 if (!BufferCopy)
1181 {
1182 *pNumAdded = 0;
1183 return NULL;
1184 }
1185 memcpy(BufferCopy, Buffer, dwSize);
1186
1187 LoadFont.pFileName = NULL;
1188 LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
1189 LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
1190 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1191 LoadFont.IsTrueType = FALSE;
1192 LoadFont.PrivateEntry = NULL;
1193 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1194
1195 RtlFreeUnicodeString(&LoadFont.RegValueName);
1196
1197 /* Release our copy */
1198 IntLockFreeType;
1199 SharedMem_Release(LoadFont.Memory);
1200 IntUnLockFreeType;
1201
1202 if (FontCount > 0)
1203 {
1204 EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
1205 if (EntryCollection)
1206 {
1207 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1208 EntryCollection->Entry = LoadFont.PrivateEntry;
1209 IntLockProcessPrivateFonts(Win32Process);
1210 EntryCollection->Handle = ++Win32Process->PrivateMemFontHandleCount;
1211 InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
1212 IntUnLockProcessPrivateFonts(Win32Process);
1213 Ret = (HANDLE)EntryCollection->Handle;
1214 }
1215 }
1216 *pNumAdded = FontCount;
1217
1218 return Ret;
1219 }
1220
1221 // FIXME: Add RemoveFontResource
1222
1223 static VOID FASTCALL
1224 CleanupFontEntry(PFONT_ENTRY FontEntry)
1225 {
1226 PFONTGDI FontGDI = FontEntry->Font;
1227 PSHARED_FACE SharedFace = FontGDI->SharedFace;
1228
1229 if (FontGDI->Filename)
1230 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1231
1232 EngFreeMem(FontGDI);
1233 SharedFace_Release(SharedFace);
1234 ExFreePoolWithTag(FontEntry, TAG_FONT);
1235 }
1236
1237 VOID FASTCALL
1238 IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
1239 {
1240 PLIST_ENTRY Entry;
1241 PFONT_ENTRY_MEM FontEntry;
1242
1243 while (!IsListEmpty(&Head->ListEntry))
1244 {
1245 Entry = RemoveHeadList(&Head->ListEntry);
1246 FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
1247
1248 CleanupFontEntry(FontEntry->Entry);
1249 ExFreePoolWithTag(FontEntry, TAG_FONT);
1250 }
1251
1252 CleanupFontEntry(Head->Entry);
1253 ExFreePoolWithTag(Head, TAG_FONT);
1254 }
1255
1256 static VOID FASTCALL
1257 UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)
1258 {
1259 PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
1260 PLIST_ENTRY ListEntry;
1261 RemoveEntryList(&Collection->ListEntry);
1262
1263 do {
1264 /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
1265 RemoveEntryList(&FontMemEntry->Entry->ListEntry);
1266
1267 ListEntry = FontMemEntry->ListEntry.Flink;
1268 FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
1269
1270 } while (FontMemEntry != Collection->Entry);
1271 }
1272
1273 BOOL FASTCALL
1274 IntGdiRemoveFontMemResource(HANDLE hMMFont)
1275 {
1276 PLIST_ENTRY Entry;
1277 PFONT_ENTRY_COLL_MEM CurrentEntry;
1278 PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
1279 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1280
1281 IntLockProcessPrivateFonts(Win32Process);
1282 Entry = Win32Process->PrivateMemFontListHead.Flink;
1283 while (Entry != &Win32Process->PrivateMemFontListHead)
1284 {
1285 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1286
1287 if (CurrentEntry->Handle == (UINT)hMMFont)
1288 {
1289 EntryCollection = CurrentEntry;
1290 UnlinkFontMemCollection(CurrentEntry);
1291 break;
1292 }
1293
1294 Entry = Entry->Flink;
1295 }
1296 IntUnLockProcessPrivateFonts(Win32Process);
1297
1298 if (EntryCollection)
1299 {
1300 IntGdiCleanupMemEntry(EntryCollection->Entry);
1301 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1302 return TRUE;
1303 }
1304 return FALSE;
1305 }
1306
1307
1308 VOID FASTCALL
1309 IntGdiCleanupPrivateFontsForProcess(VOID)
1310 {
1311 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1312 PLIST_ENTRY Entry;
1313 PFONT_ENTRY_COLL_MEM EntryCollection;
1314
1315 DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
1316 do {
1317 Entry = NULL;
1318 EntryCollection = NULL;
1319
1320 IntLockProcessPrivateFonts(Win32Process);
1321 if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
1322 {
1323 Entry = Win32Process->PrivateMemFontListHead.Flink;
1324 EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1325 UnlinkFontMemCollection(EntryCollection);
1326 }
1327 IntUnLockProcessPrivateFonts(Win32Process);
1328
1329 if (EntryCollection)
1330 {
1331 IntGdiCleanupMemEntry(EntryCollection->Entry);
1332 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1333 }
1334 else
1335 {
1336 /* No Mem fonts anymore, see if we have any other private fonts left */
1337 Entry = NULL;
1338 IntLockProcessPrivateFonts(Win32Process);
1339 if (!IsListEmpty(&Win32Process->PrivateFontListHead))
1340 {
1341 Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
1342 }
1343 IntUnLockProcessPrivateFonts(Win32Process);
1344
1345 if (Entry)
1346 {
1347 CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
1348 }
1349 }
1350
1351 } while (Entry);
1352 }
1353
1354 BOOL FASTCALL
1355 IntIsFontRenderingEnabled(VOID)
1356 {
1357 BOOL Ret = RenderingEnabled;
1358 HDC hDC;
1359
1360 hDC = IntGetScreenDC();
1361 if (hDC)
1362 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
1363
1364 return Ret;
1365 }
1366
1367 VOID FASTCALL
1368 IntEnableFontRendering(BOOL Enable)
1369 {
1370 RenderingEnabled = Enable;
1371 }
1372
1373 FT_Render_Mode FASTCALL
1374 IntGetFontRenderMode(LOGFONTW *logfont)
1375 {
1376 switch (logfont->lfQuality)
1377 {
1378 case ANTIALIASED_QUALITY:
1379 case NONANTIALIASED_QUALITY:
1380 return FT_RENDER_MODE_MONO;
1381 case DRAFT_QUALITY:
1382 return FT_RENDER_MODE_LIGHT;
1383 /* case CLEARTYPE_QUALITY:
1384 return FT_RENDER_MODE_LCD; */
1385 }
1386 return FT_RENDER_MODE_NORMAL;
1387 }
1388
1389
1390 NTSTATUS FASTCALL
1391 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
1392 {
1393 PLFONT plfont;
1394 LOGFONTW *plf;
1395
1396 plfont = LFONT_AllocFontWithHandle();
1397 if (!plfont)
1398 {
1399 return STATUS_NO_MEMORY;
1400 }
1401
1402 ExInitializePushLock(&plfont->lock);
1403 *NewFont = plfont->BaseObject.hHmgr;
1404 plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
1405 RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
1406 if (lf->lfEscapement != lf->lfOrientation)
1407 {
1408 /* This should really depend on whether GM_ADVANCED is set */
1409 plf->lfOrientation = plf->lfEscapement;
1410 }
1411 LFONT_UnlockFont(plfont);
1412
1413 return STATUS_SUCCESS;
1414 }
1415
1416 /*************************************************************************
1417 * TranslateCharsetInfo
1418 *
1419 * Fills a CHARSETINFO structure for a character set, code page, or
1420 * font. This allows making the correspondance between different labelings
1421 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
1422 * of the same encoding.
1423 *
1424 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
1425 * only one codepage should be set in *Src.
1426 *
1427 * RETURNS
1428 * TRUE on success, FALSE on failure.
1429 *
1430 */
1431 static BOOLEAN APIENTRY
1432 IntTranslateCharsetInfo(PDWORD Src, /* [in]
1433 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
1434 if flags == TCI_SRCCHARSET: a character set value
1435 if flags == TCI_SRCCODEPAGE: a code page value */
1436 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
1437 DWORD Flags /* [in] determines interpretation of lpSrc */)
1438 {
1439 int Index = 0;
1440
1441 switch (Flags)
1442 {
1443 case TCI_SRCFONTSIG:
1444 while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
1445 {
1446 Index++;
1447 }
1448 break;
1449 case TCI_SRCCODEPAGE:
1450 while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciACP)
1451 {
1452 Index++;
1453 }
1454 break;
1455 case TCI_SRCCHARSET:
1456 while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciCharset)
1457 {
1458 Index++;
1459 }
1460 break;
1461 default:
1462 return FALSE;
1463 }
1464
1465 if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == FontTci[Index].ciCharset)
1466 {
1467 return FALSE;
1468 }
1469
1470 RtlCopyMemory(Cs, &FontTci[Index], sizeof(CHARSETINFO));
1471
1472 return TRUE;
1473 }
1474
1475
1476 static BOOL face_has_symbol_charmap(FT_Face ft_face)
1477 {
1478 int i;
1479
1480 for(i = 0; i < ft_face->num_charmaps; i++)
1481 {
1482 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
1483 return TRUE;
1484 }
1485 return FALSE;
1486 }
1487
1488
1489 static void FASTCALL
1490 FillTMEx(TEXTMETRICW *TM, PFONTGDI FontGDI,
1491 TT_OS2 *pOS2, TT_HoriHeader *pHori,
1492 FT_WinFNT_HeaderRec *pFNT, BOOL RealFont)
1493 {
1494 FT_Fixed XScale, YScale;
1495 int Ascent, Descent;
1496 FT_Face Face = FontGDI->SharedFace->Face;
1497
1498 XScale = Face->size->metrics.x_scale;
1499 YScale = Face->size->metrics.y_scale;
1500
1501 if (pFNT)
1502 {
1503 TM->tmHeight = pFNT->pixel_height;
1504 TM->tmAscent = pFNT->ascent;
1505 TM->tmDescent = TM->tmHeight - TM->tmAscent;
1506 TM->tmInternalLeading = pFNT->internal_leading;
1507 TM->tmExternalLeading = pFNT->external_leading;
1508 TM->tmAveCharWidth = pFNT->avg_width;
1509 TM->tmMaxCharWidth = pFNT->max_width;
1510 TM->tmOverhang = 0;
1511 TM->tmDigitizedAspectX = pFNT->horizontal_resolution;
1512 TM->tmDigitizedAspectY = pFNT->vertical_resolution;
1513 TM->tmFirstChar = pFNT->first_char;
1514 TM->tmLastChar = pFNT->last_char;
1515 TM->tmDefaultChar = pFNT->default_char + pFNT->first_char;
1516 TM->tmBreakChar = pFNT->break_char + pFNT->first_char;
1517 TM->tmPitchAndFamily = pFNT->pitch_and_family;
1518 if (RealFont)
1519 {
1520 TM->tmWeight = FontGDI->OriginalWeight;
1521 TM->tmItalic = FontGDI->OriginalItalic;
1522 TM->tmUnderlined = pFNT->underline;
1523 TM->tmStruckOut = pFNT->strike_out;
1524 TM->tmCharSet = pFNT->charset;
1525 }
1526 else
1527 {
1528 TM->tmWeight = FontGDI->RequestWeight;
1529 TM->tmItalic = FontGDI->RequestItalic;
1530 TM->tmUnderlined = FontGDI->RequestUnderline;
1531 TM->tmStruckOut = FontGDI->RequestStrikeOut;
1532 TM->tmCharSet = FontGDI->CharSet;
1533 }
1534 return;
1535 }
1536
1537 if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
1538 {
1539 Ascent = pHori->Ascender;
1540 Descent = -pHori->Descender;
1541 }
1542 else
1543 {
1544 Ascent = pOS2->usWinAscent;
1545 Descent = pOS2->usWinDescent;
1546 }
1547
1548 #if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */
1549 TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
1550 TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
1551 #else /* This (ros) code was previously affected by a FreeType bug, but it works now */
1552 TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* Units above baseline */
1553 TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* Units below baseline */
1554 #endif
1555 TM->tmInternalLeading = (FT_MulFix(Ascent + Descent - Face->units_per_EM, YScale) + 32) >> 6;
1556
1557 TM->tmHeight = TM->tmAscent + TM->tmDescent;
1558
1559 /* MSDN says:
1560 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1561 */
1562 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
1563 - ((Ascent + Descent)
1564 - (pHori->Ascender - pHori->Descender)),
1565 YScale) + 32) >> 6);
1566
1567 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
1568 if (TM->tmAveCharWidth == 0)
1569 {
1570 TM->tmAveCharWidth = 1;
1571 }
1572
1573 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
1574 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
1575
1576 if (RealFont)
1577 {
1578 TM->tmWeight = FontGDI->OriginalWeight;
1579 }
1580 else
1581 {
1582 if (FontGDI->OriginalWeight != FW_DONTCARE &&
1583 FontGDI->OriginalWeight != FW_NORMAL)
1584 {
1585 TM->tmWeight = FontGDI->OriginalWeight;
1586 }
1587 else
1588 {
1589 TM->tmWeight = FontGDI->RequestWeight;
1590 }
1591 }
1592
1593 TM->tmOverhang = 0;
1594 TM->tmDigitizedAspectX = 96;
1595 TM->tmDigitizedAspectY = 96;
1596 if (face_has_symbol_charmap(Face) ||
1597 (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
1598 {
1599 USHORT cpOEM, cpAnsi;
1600
1601 EngGetCurrentCodePage(&cpOEM, &cpAnsi);
1602 TM->tmFirstChar = 0;
1603 switch(cpAnsi)
1604 {
1605 case 1257: /* Baltic */
1606 TM->tmLastChar = 0xf8fd;
1607 break;
1608 default:
1609 TM->tmLastChar = 0xf0ff;
1610 }
1611 TM->tmBreakChar = 0x20;
1612 TM->tmDefaultChar = 0x1f;
1613 }
1614 else
1615 {
1616 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
1617 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
1618
1619 if(pOS2->usFirstCharIndex <= 1)
1620 TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
1621 else if (pOS2->usFirstCharIndex > 0xff)
1622 TM->tmBreakChar = 0x20;
1623 else
1624 TM->tmBreakChar = pOS2->usFirstCharIndex;
1625 TM->tmDefaultChar = TM->tmBreakChar - 1;
1626 }
1627
1628 if (RealFont)
1629 {
1630 TM->tmItalic = FontGDI->OriginalItalic;
1631 TM->tmUnderlined = FALSE;
1632 TM->tmStruckOut = FALSE;
1633 }
1634 else
1635 {
1636 if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
1637 {
1638 TM->tmItalic = 0xFF;
1639 }
1640 else
1641 {
1642 TM->tmItalic = 0;
1643 }
1644 TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
1645 TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
1646 }
1647
1648 if (!FT_IS_FIXED_WIDTH(Face))
1649 {
1650 switch (pOS2->panose[PAN_PROPORTION_INDEX])
1651 {
1652 case PAN_PROP_MONOSPACED:
1653 TM->tmPitchAndFamily = 0;
1654 break;
1655 default:
1656 TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH;
1657 break;
1658 }
1659 }
1660 else
1661 {
1662 TM->tmPitchAndFamily = 0;
1663 }
1664
1665 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
1666 {
1667 case PAN_FAMILY_SCRIPT:
1668 TM->tmPitchAndFamily |= FF_SCRIPT;
1669 break;
1670 case PAN_FAMILY_DECORATIVE:
1671 TM->tmPitchAndFamily |= FF_DECORATIVE;
1672 break;
1673
1674 case PAN_ANY:
1675 case PAN_NO_FIT:
1676 case PAN_FAMILY_TEXT_DISPLAY:
1677 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
1678 /* Which is clearly not what the panose spec says. */
1679 if (TM->tmPitchAndFamily == 0) /* Fixed */
1680 {
1681 TM->tmPitchAndFamily = FF_MODERN;
1682 }
1683 else
1684 {
1685 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
1686 {
1687 case PAN_ANY:
1688 case PAN_NO_FIT:
1689 default:
1690 TM->tmPitchAndFamily |= FF_DONTCARE;
1691 break;
1692
1693 case PAN_SERIF_COVE:
1694 case PAN_SERIF_OBTUSE_COVE:
1695 case PAN_SERIF_SQUARE_COVE:
1696 case PAN_SERIF_OBTUSE_SQUARE_COVE:
1697 case PAN_SERIF_SQUARE:
1698 case PAN_SERIF_THIN:
1699 case PAN_SERIF_BONE:
1700 case PAN_SERIF_EXAGGERATED:
1701 case PAN_SERIF_TRIANGLE:
1702 TM->tmPitchAndFamily |= FF_ROMAN;
1703 break;
1704
1705 case PAN_SERIF_NORMAL_SANS:
1706 case PAN_SERIF_OBTUSE_SANS:
1707 case PAN_SERIF_PERP_SANS:
1708 case PAN_SERIF_FLARED:
1709 case PAN_SERIF_ROUNDED:
1710 TM->tmPitchAndFamily |= FF_SWISS;
1711 break;
1712 }
1713 }
1714 break;
1715 default:
1716 TM->tmPitchAndFamily |= FF_DONTCARE;
1717 }
1718
1719 if (FT_IS_SCALABLE(Face))
1720 {
1721 TM->tmPitchAndFamily |= TMPF_VECTOR;
1722 }
1723 if (FT_IS_SFNT(Face))
1724 {
1725 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
1726 }
1727
1728 TM->tmCharSet = FontGDI->CharSet;
1729 }
1730
1731 static void FASTCALL
1732 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
1733 TT_OS2 *pOS2, TT_HoriHeader *pHori,
1734 FT_WinFNT_HeaderRec *pFNT)
1735 {
1736 FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
1737 }
1738
1739 /*************************************************************
1740 * IntGetOutlineTextMetrics
1741 *
1742 */
1743 INT FASTCALL
1744 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
1745 UINT Size,
1746 OUTLINETEXTMETRICW *Otm)
1747 {
1748 unsigned Needed;
1749 TT_OS2 *pOS2;
1750 TT_HoriHeader *pHori;
1751 TT_Postscript *pPost;
1752 FT_Fixed XScale, YScale;
1753 ANSI_STRING FamilyNameA, StyleNameA;
1754 UNICODE_STRING FamilyNameW, StyleNameW, Regular;
1755 FT_WinFNT_HeaderRec Win;
1756 FT_Error Error;
1757 char *Cp;
1758 NTSTATUS status;
1759 FT_Face Face = FontGDI->SharedFace->Face;
1760
1761 Needed = sizeof(OUTLINETEXTMETRICW);
1762
1763 RtlInitAnsiString(&FamilyNameA, Face->family_name);
1764 status = RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
1765 if (!NT_SUCCESS(status))
1766 {
1767 return 0;
1768 }
1769
1770 RtlInitAnsiString(&StyleNameA, Face->style_name);
1771 status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
1772 if (!NT_SUCCESS(status))
1773 {
1774 RtlFreeUnicodeString(&FamilyNameW);
1775 return 0;
1776 }
1777
1778 /* These names should be read from the TT name table */
1779
1780 /* Length of otmpFamilyName */
1781 Needed += FamilyNameW.Length + sizeof(WCHAR);
1782
1783 RtlInitUnicodeString(&Regular, L"Regular");
1784 /* Length of otmpFaceName */
1785 if (RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
1786 {
1787 Needed += FamilyNameW.Length + sizeof(WCHAR); /* Just the family name */
1788 }
1789 else
1790 {
1791 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
1792 }
1793
1794 /* Length of otmpStyleName */
1795 Needed += StyleNameW.Length + sizeof(WCHAR);
1796
1797 /* Length of otmpFullName */
1798 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
1799
1800 if (Size < Needed)
1801 {
1802 RtlFreeUnicodeString(&FamilyNameW);
1803 RtlFreeUnicodeString(&StyleNameW);
1804 return Needed;
1805 }
1806
1807 XScale = Face->size->metrics.x_scale;
1808 YScale = Face->size->metrics.y_scale;
1809
1810 IntLockFreeType;
1811 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
1812 if (NULL == pOS2)
1813 {
1814 IntUnLockFreeType;
1815 DPRINT1("Can't find OS/2 table - not TT font?\n");
1816 RtlFreeUnicodeString(&StyleNameW);
1817 RtlFreeUnicodeString(&FamilyNameW);
1818 return 0;
1819 }
1820
1821 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
1822 if (NULL == pHori)
1823 {
1824 IntUnLockFreeType;
1825 DPRINT1("Can't find HHEA table - not TT font?\n");
1826 RtlFreeUnicodeString(&StyleNameW);
1827 RtlFreeUnicodeString(&FamilyNameW);
1828 return 0;
1829 }
1830
1831 pPost = FT_Get_Sfnt_Table(Face, ft_sfnt_post); /* We can live with this failing */
1832
1833 Error = FT_Get_WinFNT_Header(Face , &Win);
1834
1835 Otm->otmSize = Needed;
1836
1837 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
1838
1839 Otm->otmFiller = 0;
1840 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1841 Otm->otmfsSelection = pOS2->fsSelection;
1842 Otm->otmfsType = pOS2->fsType;
1843 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1844 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1845 Otm->otmItalicAngle = 0; /* POST table */
1846 Otm->otmEMSquare = Face->units_per_EM;
1847 Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
1848 Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
1849 Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
1850 Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
1851 Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
1852 Otm->otmrcFontBox.left = (FT_MulFix(Face->bbox.xMin, XScale) + 32) >> 6;
1853 Otm->otmrcFontBox.right = (FT_MulFix(Face->bbox.xMax, XScale) + 32) >> 6;
1854 Otm->otmrcFontBox.top = (FT_MulFix(Face->bbox.yMax, YScale) + 32) >> 6;
1855 Otm->otmrcFontBox.bottom = (FT_MulFix(Face->bbox.yMin, YScale) + 32) >> 6;
1856 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
1857 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
1858 Otm->otmMacLineGap = Otm->otmLineGap;
1859 Otm->otmusMinimumPPEM = 0; /* TT Header */
1860 Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
1861 Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
1862 Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
1863 Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
1864 Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
1865 Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
1866 Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
1867 Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
1868 Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
1869 Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
1870 if (!pPost)
1871 {
1872 Otm->otmsUnderscoreSize = 0;
1873 Otm->otmsUnderscorePosition = 0;
1874 }
1875 else
1876 {
1877 Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
1878 Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
1879 }
1880
1881 IntUnLockFreeType;
1882
1883 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1884 Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
1885 Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
1886 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1887 Cp += FamilyNameW.Length + sizeof(WCHAR);
1888 Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
1889 wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
1890 Cp += StyleNameW.Length + sizeof(WCHAR);
1891 Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
1892 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1893 if (!RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
1894 {
1895 wcscat((WCHAR*) Cp, L" ");
1896 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
1897 Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
1898 }
1899 else
1900 {
1901 Cp += FamilyNameW.Length + sizeof(WCHAR);
1902 }
1903 Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
1904 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1905 wcscat((WCHAR*) Cp, L" ");
1906 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
1907
1908 RtlFreeUnicodeString(&StyleNameW);
1909 RtlFreeUnicodeString(&FamilyNameW);
1910
1911 return Needed;
1912 }
1913
1914 static PFONTGDI FASTCALL
1915 FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
1916 {
1917 PLIST_ENTRY Entry;
1918 PFONT_ENTRY CurrentEntry;
1919 ANSI_STRING EntryFaceNameA;
1920 UNICODE_STRING EntryFaceNameW;
1921 FONTGDI *FontGDI;
1922 NTSTATUS status;
1923
1924 Entry = Head->Flink;
1925 while (Entry != Head)
1926 {
1927 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1928
1929 FontGDI = CurrentEntry->Font;
1930 ASSERT(FontGDI);
1931
1932 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
1933 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
1934 if (!NT_SUCCESS(status))
1935 {
1936 break;
1937 }
1938
1939 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
1940 {
1941 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
1942 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
1943 }
1944
1945 if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE))
1946 {
1947 RtlFreeUnicodeString(&EntryFaceNameW);
1948 return FontGDI;
1949 }
1950
1951 RtlFreeUnicodeString(&EntryFaceNameW);
1952 Entry = Entry->Flink;
1953 }
1954
1955 return NULL;
1956 }
1957
1958 static PFONTGDI FASTCALL
1959 FindFaceNameInLists(PUNICODE_STRING FaceName)
1960 {
1961 PPROCESSINFO Win32Process;
1962 PFONTGDI Font;
1963
1964 /* Search the process local list.
1965 We do not have to search the 'Mem' list, since those fonts are linked in the PrivateFontListHead */
1966 Win32Process = PsGetCurrentProcessWin32Process();
1967 IntLockProcessPrivateFonts(Win32Process);
1968 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
1969 IntUnLockProcessPrivateFonts(Win32Process);
1970 if (NULL != Font)
1971 {
1972 return Font;
1973 }
1974
1975 /* Search the global list */
1976 IntLockGlobalFonts;
1977 Font = FindFaceNameInList(FaceName, &FontListHead);
1978 IntUnLockGlobalFonts;
1979
1980 return Font;
1981 }
1982
1983 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
1984 static BYTE
1985 CharSetFromLangID(LANGID LangID)
1986 {
1987 /* FIXME: Add more and fix if wrong */
1988 switch (PRIMARYLANGID(LangID))
1989 {
1990 case LANG_CHINESE:
1991 switch (SUBLANGID(LangID))
1992 {
1993 case SUBLANG_CHINESE_TRADITIONAL:
1994 return CHINESEBIG5_CHARSET;
1995 case SUBLANG_CHINESE_SIMPLIFIED:
1996 default:
1997 break;
1998 }
1999 return GB2312_CHARSET;
2000
2001 case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
2002 case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
2003 return EASTEUROPE_CHARSET;
2004
2005 case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
2006 case LANG_SERBIAN: case LANG_UKRAINIAN:
2007 return RUSSIAN_CHARSET;
2008
2009 case LANG_ARABIC: return ARABIC_CHARSET;
2010 case LANG_GREEK: return GREEK_CHARSET;
2011 case LANG_HEBREW: return HEBREW_CHARSET;
2012 case LANG_JAPANESE: return SHIFTJIS_CHARSET;
2013 case LANG_KOREAN: return JOHAB_CHARSET;
2014 case LANG_TURKISH: return TURKISH_CHARSET;
2015 case LANG_THAI: return THAI_CHARSET;
2016 case LANG_LATVIAN: return BALTIC_CHARSET;
2017 case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
2018
2019 case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
2020 case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
2021 case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
2022 case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
2023 case LANG_SWEDISH: default:
2024 return ANSI_CHARSET;
2025 }
2026 }
2027
2028 static void
2029 SwapEndian(LPVOID pvData, DWORD Size)
2030 {
2031 BYTE b, *pb = pvData;
2032 Size /= 2;
2033 while (Size-- > 0)
2034 {
2035 b = pb[0];
2036 pb[0] = pb[1];
2037 pb[1] = b;
2038 ++pb; ++pb;
2039 }
2040 }
2041
2042 static NTSTATUS
2043 IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face)
2044 {
2045 FT_SfntName Name;
2046 INT i, Count;
2047 WCHAR Buf[LF_FACESIZE];
2048 NTSTATUS Status = STATUS_NOT_FOUND;
2049
2050 RtlInitUnicodeString(pLocalNameW, NULL);
2051
2052 Count = FT_Get_Sfnt_Name_Count(Face);
2053 for (i = 0; i < Count; ++i)
2054 {
2055 FT_Get_Sfnt_Name(Face, i, &Name);
2056 if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
2057 Name.encoding_id != TT_MS_ID_UNICODE_CS)
2058 {
2059 continue; /* not Microsoft Unicode name */
2060 }
2061
2062 if (Name.name_id != TT_NAME_ID_FONT_FAMILY ||
2063 Name.string == NULL || Name.string_len == 0 ||
2064 (Name.string[0] == 0 && Name.string[1] == 0))
2065 {
2066 continue; /* not family name */
2067 }
2068
2069 if (sizeof(Buf) < Name.string_len + sizeof(UNICODE_NULL))
2070 {
2071 continue; /* name too long */
2072 }
2073
2074 /* NOTE: Name.string is not null-terminated */
2075 RtlCopyMemory(Buf, Name.string, Name.string_len);
2076 Buf[Name.string_len / sizeof(WCHAR)] = UNICODE_NULL;
2077
2078 /* Convert UTF-16 big endian to little endian */
2079 SwapEndian(Buf, Name.string_len);
2080 #if 0
2081 DPRINT("IntGetFontLocalizedName: %S (%d)\n", Buf, Name.string_len);
2082 #endif
2083
2084 Status = RtlCreateUnicodeString(pLocalNameW, Buf);
2085 break;
2086 }
2087
2088 return Status;
2089 }
2090
2091 static void FASTCALL
2092 FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
2093 {
2094 ANSI_STRING StyleA;
2095 UNICODE_STRING StyleW;
2096 TT_OS2 *pOS2;
2097 FONTSIGNATURE fs;
2098 CHARSETINFO CharSetInfo;
2099 unsigned i, Size;
2100 OUTLINETEXTMETRICW *Otm;
2101 LOGFONTW *Lf;
2102 TEXTMETRICW *TM;
2103 NEWTEXTMETRICW *Ntm;
2104 DWORD fs0;
2105 NTSTATUS status;
2106 FT_Face Face = FontGDI->SharedFace->Face;
2107
2108 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
2109 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2110 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2111 if (!Otm)
2112 {
2113 return;
2114 }
2115 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2116
2117 Lf = &Info->EnumLogFontEx.elfLogFont;
2118 TM = &Otm->otmTextMetrics;
2119
2120 Lf->lfHeight = TM->tmHeight;
2121 Lf->lfWidth = TM->tmAveCharWidth;
2122 Lf->lfWeight = TM->tmWeight;
2123 Lf->lfItalic = TM->tmItalic;
2124 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
2125 Lf->lfCharSet = TM->tmCharSet;
2126 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
2127 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
2128 Lf->lfQuality = PROOF_QUALITY;
2129
2130 Ntm = &Info->NewTextMetricEx.ntmTm;
2131 Ntm->tmHeight = TM->tmHeight;
2132 Ntm->tmAscent = TM->tmAscent;
2133 Ntm->tmDescent = TM->tmDescent;
2134 Ntm->tmInternalLeading = TM->tmInternalLeading;
2135 Ntm->tmExternalLeading = TM->tmExternalLeading;
2136 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
2137 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
2138 Ntm->tmWeight = TM->tmWeight;
2139 Ntm->tmOverhang = TM->tmOverhang;
2140 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
2141 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
2142 Ntm->tmFirstChar = TM->tmFirstChar;
2143 Ntm->tmLastChar = TM->tmLastChar;
2144 Ntm->tmDefaultChar = TM->tmDefaultChar;
2145 Ntm->tmBreakChar = TM->tmBreakChar;
2146 Ntm->tmItalic = TM->tmItalic;
2147 Ntm->tmUnderlined = TM->tmUnderlined;
2148 Ntm->tmStruckOut = TM->tmStruckOut;
2149 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
2150 Ntm->tmCharSet = TM->tmCharSet;
2151 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
2152
2153 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
2154
2155 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
2156
2157 Ntm->ntmSizeEM = Otm->otmEMSquare;
2158 Ntm->ntmCellHeight = Otm->otmEMSquare;
2159 Ntm->ntmAvgWidth = 0;
2160
2161 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
2162 ? TRUETYPE_FONTTYPE : 0);
2163
2164 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
2165 Info->FontType |= RASTER_FONTTYPE;
2166
2167 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2168
2169 /* try the localized name */
2170 status = STATUS_UNSUCCESSFUL;
2171 if (CharSetFromLangID(gusLanguageID) == FontGDI->CharSet)
2172 {
2173 /* get localized name */
2174 UNICODE_STRING LocalNameW;
2175 status = IntGetFontLocalizedName(&LocalNameW, Face);
2176 if (NT_SUCCESS(status))
2177 {
2178 /* store it */
2179 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
2180 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
2181 LocalNameW.Buffer);
2182 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2183 sizeof(Info->EnumLogFontEx.elfFullName),
2184 LocalNameW.Buffer);
2185 }
2186 RtlFreeUnicodeString(&LocalNameW);
2187 }
2188
2189 /* if localized name was unavailable */
2190 if (!NT_SUCCESS(status))
2191 {
2192 /* store English name */
2193 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
2194 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
2195 FaceName);
2196 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2197 sizeof(Info->EnumLogFontEx.elfFullName),
2198 FaceName);
2199 }
2200
2201 RtlInitAnsiString(&StyleA, Face->style_name);
2202 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
2203 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
2204 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
2205 if (!NT_SUCCESS(status))
2206 {
2207 return;
2208 }
2209 if (StyleW.Length)
2210 {
2211 if (wcslen(Info->EnumLogFontEx.elfFullName) +
2212 StyleW.Length / sizeof(WCHAR) + 1 <=
2213 sizeof(Info->EnumLogFontEx.elfFullName))
2214 {
2215 wcscat(Info->EnumLogFontEx.elfFullName, L" ");
2216 wcscat(Info->EnumLogFontEx.elfFullName, StyleW.Buffer);
2217 }
2218 }
2219
2220 Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
2221 Info->EnumLogFontEx.elfScript[0] = L'\0';
2222 IntLockFreeType;
2223 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2224
2225 if (!pOS2)
2226 {
2227 IntUnLockFreeType;
2228 return;
2229 }
2230
2231 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2232 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2233 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2234 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2235 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2236 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2237
2238 if (0 == pOS2->version)
2239 {
2240 FT_UInt Dummy;
2241
2242 if (FT_Get_First_Char(Face, &Dummy) < 0x100)
2243 fs.fsCsb[0] |= FS_LATIN1;
2244 else
2245 fs.fsCsb[0] |= FS_SYMBOL;
2246 }
2247 IntUnLockFreeType;
2248
2249 if (fs.fsCsb[0] == 0)
2250 {
2251 /* Let's see if we can find any interesting cmaps */
2252 for (i = 0; i < (UINT)Face->num_charmaps; i++)
2253 {
2254 switch (Face->charmaps[i]->encoding)
2255 {
2256 case FT_ENCODING_UNICODE:
2257 case FT_ENCODING_APPLE_ROMAN:
2258 fs.fsCsb[0] |= FS_LATIN1;
2259 break;
2260 case FT_ENCODING_MS_SYMBOL:
2261 fs.fsCsb[0] |= FS_SYMBOL;
2262 break;
2263 default:
2264 break;
2265 }
2266 }
2267 }
2268
2269 for (i = 0; i < MAXTCIINDEX; i++)
2270 {
2271 fs0 = 1L << i;
2272 if (fs.fsCsb[0] & fs0)
2273 {
2274 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
2275 {
2276 CharSetInfo.ciCharset = DEFAULT_CHARSET;
2277 }
2278 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
2279 {
2280 Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
2281 if (ElfScripts[i])
2282 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
2283 else
2284 {
2285 DPRINT1("Unknown elfscript for bit %u\n", i);
2286 }
2287 }
2288 }
2289 }
2290 Info->NewTextMetricEx.ntmFontSig = fs;
2291 }
2292
2293 static int FASTCALL
2294 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
2295 {
2296 DWORD i;
2297 UNICODE_STRING InfoFaceName;
2298
2299 for (i = 0; i < InfoEntries; i++)
2300 {
2301 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
2302 if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE))
2303 {
2304 return i;
2305 }
2306 }
2307
2308 return -1;
2309 }
2310
2311 static BOOLEAN FASTCALL
2312 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
2313 PFONTFAMILYINFO Info, DWORD InfoEntries)
2314 {
2315 UNICODE_STRING LogFontFaceName;
2316
2317 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
2318 if (0 != LogFontFaceName.Length &&
2319 !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE))
2320 {
2321 return FALSE;
2322 }
2323
2324 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
2325 }
2326
2327 static BOOLEAN FASTCALL
2328 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
2329 PFONTFAMILYINFO Info,
2330 DWORD *Count,
2331 DWORD Size,
2332 PLIST_ENTRY Head)
2333 {
2334 PLIST_ENTRY Entry;
2335 PFONT_ENTRY CurrentEntry;
2336 ANSI_STRING EntryFaceNameA;
2337 UNICODE_STRING EntryFaceNameW;
2338 FONTGDI *FontGDI;
2339 NTSTATUS status;
2340
2341 Entry = Head->Flink;
2342 while (Entry != Head)
2343 {
2344 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2345
2346 FontGDI = CurrentEntry->Font;
2347 ASSERT(FontGDI);
2348
2349 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
2350 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2351 if (!NT_SUCCESS(status))
2352 {
2353 return FALSE;
2354 }
2355
2356 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2357 {
2358 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2359 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2360 }
2361
2362 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
2363 {
2364 if (*Count < Size)
2365 {
2366 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
2367 }
2368 (*Count)++;
2369 }
2370 RtlFreeUnicodeString(&EntryFaceNameW);
2371 Entry = Entry->Flink;
2372 }
2373
2374 return TRUE;
2375 }
2376
2377 typedef struct FontFamilyInfoCallbackContext
2378 {
2379 LPLOGFONTW LogFont;
2380 PFONTFAMILYINFO Info;
2381 DWORD Count;
2382 DWORD Size;
2383 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
2384
2385 _Function_class_(RTL_QUERY_REGISTRY_ROUTINE)
2386 static NTSTATUS APIENTRY
2387 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
2388 IN PVOID ValueData, IN ULONG ValueLength,
2389 IN PVOID Context, IN PVOID EntryContext)
2390 {
2391 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
2392 UNICODE_STRING RegistryName, RegistryValue;
2393 int Existing;
2394 PFONTGDI FontGDI;
2395
2396 if (REG_SZ != ValueType)
2397 {
2398 return STATUS_SUCCESS;
2399 }
2400 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
2401 RtlInitUnicodeString(&RegistryName, ValueName);
2402
2403 /* Do we need to include this font family? */
2404 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
2405 min(InfoContext->Count, InfoContext->Size)))
2406 {
2407 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
2408 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
2409 min(InfoContext->Count, InfoContext->Size));
2410 if (0 <= Existing)
2411 {
2412 /* We already have the information about the "real" font. Just copy it */
2413 if (InfoContext->Count < InfoContext->Size)
2414 {
2415 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
2416 RtlStringCbCopyNW(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
2417 sizeof(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName),
2418 RegistryName.Buffer,
2419 RegistryName.Length);
2420 }
2421 InfoContext->Count++;
2422 return STATUS_SUCCESS;
2423 }
2424
2425 /* Try to find information about the "real" font */
2426 FontGDI = FindFaceNameInLists(&RegistryValue);
2427 if (NULL == FontGDI)
2428 {
2429 /* "Real" font not found, discard this registry entry */
2430 return STATUS_SUCCESS;
2431 }
2432
2433 /* Return info about the "real" font but with the name of the alias */
2434 if (InfoContext->Count < InfoContext->Size)
2435 {
2436 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
2437 RegistryName.Buffer, FontGDI);
2438 }
2439 InfoContext->Count++;
2440 return STATUS_SUCCESS;
2441 }
2442
2443 return STATUS_SUCCESS;
2444 }
2445
2446 static BOOLEAN FASTCALL
2447 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
2448 PFONTFAMILYINFO Info,
2449 DWORD *Count,
2450 DWORD Size)
2451 {
2452 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2453 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
2454 NTSTATUS Status;
2455
2456 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
2457 The real work is done in the registry callback function */
2458 Context.LogFont = LogFont;
2459 Context.Info = Info;
2460 Context.Count = *Count;
2461 Context.Size = Size;
2462
2463 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
2464 QueryTable[0].Flags = 0;
2465 QueryTable[0].Name = NULL;
2466 QueryTable[0].EntryContext = NULL;
2467 QueryTable[0].DefaultType = REG_NONE;
2468 QueryTable[0].DefaultData = NULL;
2469 QueryTable[0].DefaultLength = 0;
2470
2471 QueryTable[1].QueryRoutine = NULL;
2472 QueryTable[1].Name = NULL;
2473
2474 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2475 L"FontSubstitutes",
2476 QueryTable,
2477 &Context,
2478 NULL);
2479 if (NT_SUCCESS(Status))
2480 {
2481 *Count = Context.Count;
2482 }
2483
2484 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
2485 }
2486
2487 BOOL
2488 FASTCALL
2489 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
2490 {
2491 if ( lprs )
2492 {
2493 lprs->nSize = sizeof(RASTERIZER_STATUS);
2494 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
2495 lprs->nLanguageID = gusLanguageID;
2496 return TRUE;
2497 }
2498 EngSetLastError(ERROR_INVALID_PARAMETER);
2499 return FALSE;
2500 }
2501
2502 static
2503 BOOL
2504 SameScaleMatrix(
2505 PMATRIX pmx1,
2506 PMATRIX pmx2)
2507 {
2508 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
2509 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
2510 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
2511 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
2512 }
2513
2514 FT_BitmapGlyph APIENTRY
2515 ftGdiGlyphCacheGet(
2516 FT_Face Face,
2517 INT GlyphIndex,
2518 INT Height,
2519 PMATRIX pmx)
2520 {
2521 PLIST_ENTRY CurrentEntry;
2522 PFONT_CACHE_ENTRY FontEntry;
2523
2524 ASSERT_FREETYPE_LOCK_HELD();
2525
2526 CurrentEntry = FontCacheListHead.Flink;
2527 while (CurrentEntry != &FontCacheListHead)
2528 {
2529 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
2530 if ((FontEntry->Face == Face) &&
2531 (FontEntry->GlyphIndex == GlyphIndex) &&
2532 (FontEntry->Height == Height) &&
2533 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2534 break;
2535 CurrentEntry = CurrentEntry->Flink;
2536 }
2537
2538 if (CurrentEntry == &FontCacheListHead)
2539 {
2540 return NULL;
2541 }
2542
2543 RemoveEntryList(CurrentEntry);
2544 InsertHeadList(&FontCacheListHead, CurrentEntry);
2545 return FontEntry->BitmapGlyph;
2546 }
2547
2548 /* no cache */
2549 FT_BitmapGlyph APIENTRY
2550 ftGdiGlyphSet(
2551 FT_Face Face,
2552 FT_GlyphSlot GlyphSlot,
2553 FT_Render_Mode RenderMode)
2554 {
2555 FT_Glyph Glyph;
2556 INT error;
2557 FT_Bitmap AlignedBitmap;
2558 FT_BitmapGlyph BitmapGlyph;
2559
2560 error = FT_Get_Glyph(GlyphSlot, &Glyph);
2561 if (error)
2562 {
2563 DPRINT1("Failure getting glyph.\n");
2564 return NULL;
2565 }
2566
2567 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2568 if (error)
2569 {
2570 FT_Done_Glyph(Glyph);
2571 DPRINT1("Failure rendering glyph.\n");
2572 return NULL;
2573 }
2574
2575 BitmapGlyph = (FT_BitmapGlyph)Glyph;
2576 FT_Bitmap_New(&AlignedBitmap);
2577 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2578 {
2579 DPRINT1("Conversion failed\n");
2580 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2581 return NULL;
2582 }
2583
2584 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2585 BitmapGlyph->bitmap = AlignedBitmap;
2586
2587 return BitmapGlyph;
2588 }
2589
2590 FT_BitmapGlyph APIENTRY
2591 ftGdiGlyphCacheSet(
2592 FT_Face Face,
2593 INT GlyphIndex,
2594 INT Height,
2595 PMATRIX pmx,
2596 FT_GlyphSlot GlyphSlot,
2597 FT_Render_Mode RenderMode)
2598 {
2599 FT_Glyph GlyphCopy;
2600 INT error;
2601 PFONT_CACHE_ENTRY NewEntry;
2602 FT_Bitmap AlignedBitmap;
2603 FT_BitmapGlyph BitmapGlyph;
2604
2605 ASSERT_FREETYPE_LOCK_HELD();
2606
2607 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2608 if (error)
2609 {
2610 DPRINT1("Failure caching glyph.\n");
2611 return NULL;
2612 };
2613
2614 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2615 if (error)
2616 {
2617 FT_Done_Glyph(GlyphCopy);
2618 DPRINT1("Failure rendering glyph.\n");
2619 return NULL;
2620 };
2621
2622 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
2623 if (!NewEntry)
2624 {
2625 DPRINT1("Alloc failure caching glyph.\n");
2626 FT_Done_Glyph(GlyphCopy);
2627 return NULL;
2628 }
2629
2630 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2631 FT_Bitmap_New(&AlignedBitmap);
2632 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2633 {
2634 DPRINT1("Conversion failed\n");
2635 ExFreePoolWithTag(NewEntry, TAG_FONT);
2636 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2637 return NULL;
2638 }
2639
2640 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2641 BitmapGlyph->bitmap = AlignedBitmap;
2642
2643 NewEntry->GlyphIndex = GlyphIndex;
2644 NewEntry->Face = Face;
2645 NewEntry->BitmapGlyph = BitmapGlyph;
2646 NewEntry->Height = Height;
2647 NewEntry->mxWorldToDevice = *pmx;
2648
2649 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
2650 if (++FontCacheNumEntries > MAX_FONT_CACHE)
2651 {
2652 NewEntry = CONTAINING_RECORD(FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
2653 RemoveCachedEntry(NewEntry);
2654 }
2655
2656 return BitmapGlyph;
2657 }
2658
2659
2660 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2661 {
2662 pt->x.value = vec->x >> 6;
2663 pt->x.fract = (vec->x & 0x3f) << 10;
2664 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2665 pt->y.value = vec->y >> 6;
2666 pt->y.fract = (vec->y & 0x3f) << 10;
2667 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2668 }
2669
2670 /*
2671 This function builds an FT_Fixed from a float. It puts the integer part
2672 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2673 It fails if the integer part of the float number is greater than SHORT_MAX.
2674 */
2675 static __inline FT_Fixed FT_FixedFromFloat(float f)
2676 {
2677 short value = f;
2678 unsigned short fract = (f - value) * 0xFFFF;
2679 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2680 }
2681
2682 /*
2683 This function builds an FT_Fixed from a FIXED. It simply put f.value
2684 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2685 */
2686 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2687 {
2688 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2689 }
2690
2691 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2692 {
2693 TTPOLYGONHEADER *pph;
2694 TTPOLYCURVE *ppc;
2695 int needed = 0, point = 0, contour, first_pt;
2696 unsigned int pph_start, cpfx;
2697 DWORD type;
2698
2699 for (contour = 0; contour < outline->n_contours; contour++)
2700 {
2701 /* Ignore contours containing one point */
2702 if (point == outline->contours[contour])
2703 {
2704 point++;
2705 continue;
2706 }
2707
2708 pph_start = needed;
2709 pph = (TTPOLYGONHEADER *)(buf + needed);
2710 first_pt = point;
2711 if (buf)
2712 {
2713 pph->dwType = TT_POLYGON_TYPE;
2714 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2715 }
2716 needed += sizeof(*pph);
2717 point++;
2718 while (point <= outline->contours[contour])
2719 {
2720 ppc = (TTPOLYCURVE *)(buf + needed);
2721 type = outline->tags[point] & FT_Curve_Tag_On ?
2722 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2723 cpfx = 0;
2724 do
2725 {
2726 if (buf)
2727 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2728 cpfx++;
2729 point++;
2730 } while (point <= outline->contours[contour] &&
2731 (outline->tags[point] & FT_Curve_Tag_On) ==
2732 (outline->tags[point-1] & FT_Curve_Tag_On));
2733 /* At the end of a contour Windows adds the start point, but
2734 only for Beziers */
2735 if (point > outline->contours[contour] &&
2736 !(outline->tags[point-1] & FT_Curve_Tag_On))
2737 {
2738 if (buf)
2739 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2740 cpfx++;
2741 }
2742 else if (point <= outline->contours[contour] &&
2743 outline->tags[point] & FT_Curve_Tag_On)
2744 {
2745 /* add closing pt for bezier */
2746 if (buf)
2747 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2748 cpfx++;
2749 point++;
2750 }
2751 if (buf)
2752 {
2753 ppc->wType = type;
2754 ppc->cpfx = cpfx;
2755 }
2756 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2757 }
2758 if (buf)
2759 pph->cb = needed - pph_start;
2760 }
2761 return needed;
2762 }
2763
2764 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2765 {
2766 /* Convert the quadratic Beziers to cubic Beziers.
2767 The parametric eqn for a cubic Bezier is, from PLRM:
2768 r(t) = at^3 + bt^2 + ct + r0
2769 with the control points:
2770 r1 = r0 + c/3
2771 r2 = r1 + (c + b)/3
2772 r3 = r0 + c + b + a
2773
2774 A quadratic Bezier has the form:
2775 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2776
2777 So equating powers of t leads to:
2778 r1 = 2/3 p1 + 1/3 p0
2779 r2 = 2/3 p1 + 1/3 p2
2780 and of course r0 = p0, r3 = p2
2781 */
2782 int contour, point = 0, first_pt;
2783 TTPOLYGONHEADER *pph;
2784 TTPOLYCURVE *ppc;
2785 DWORD pph_start, cpfx, type;
2786 FT_Vector cubic_control[4];
2787 unsigned int needed = 0;
2788
2789 for (contour = 0; contour < outline->n_contours; contour++)
2790 {
2791 pph_start = needed;
2792 pph = (TTPOLYGONHEADER *)(buf + needed);
2793 first_pt = point;
2794 if (buf)
2795 {
2796 pph->dwType = TT_POLYGON_TYPE;
2797 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2798 }
2799 needed += sizeof(*pph);
2800 point++;
2801 while (point <= outline->contours[contour])
2802 {
2803 ppc = (TTPOLYCURVE *)(buf + needed);
2804 type = outline->tags[point] & FT_Curve_Tag_On ?
2805 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2806 cpfx = 0;
2807 do
2808 {
2809 if (type == TT_PRIM_LINE)
2810 {
2811 if (buf)
2812 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2813 cpfx++;
2814 point++;
2815 }
2816 else
2817 {
2818 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2819 so cpfx = 3n */
2820
2821 /* FIXME: Possible optimization in endpoint calculation
2822 if there are two consecutive curves */
2823 cubic_control[0] = outline->points[point-1];
2824 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2825 {
2826 cubic_control[0].x += outline->points[point].x + 1;
2827 cubic_control[0].y += outline->points[point].y + 1;
2828 cubic_control[0].x >>= 1;
2829 cubic_control[0].y >>= 1;
2830 }
2831 if (point+1 > outline->contours[contour])
2832 cubic_control[3] = outline->points[first_pt];
2833 else
2834 {
2835 cubic_control[3] = outline->points[point+1];
2836 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2837 {
2838 cubic_control[3].x += outline->points[point].x + 1;
2839 cubic_control[3].y += outline->points[point].y + 1;
2840 cubic_control[3].x >>= 1;
2841 cubic_control[3].y >>= 1;
2842 }
2843 }
2844 /* r1 = 1/3 p0 + 2/3 p1
2845 r2 = 1/3 p2 + 2/3 p1 */
2846 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2847 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2848 cubic_control[2] = cubic_control[1];
2849 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2850 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2851 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2852 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2853 if (buf)
2854 {
2855 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2856 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2857 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2858 }
2859 cpfx += 3;
2860 point++;
2861 }
2862 } while (point <= outline->contours[contour] &&
2863 (outline->tags[point] & FT_Curve_Tag_On) ==
2864 (outline->tags[point-1] & FT_Curve_Tag_On));
2865 /* At the end of a contour Windows adds the start point,
2866 but only for Beziers and we've already done that.
2867 */
2868 if (point <= outline->contours[contour] &&
2869 outline->tags[point] & FT_Curve_Tag_On)
2870 {
2871 /* This is the closing pt of a bezier, but we've already
2872 added it, so just inc point and carry on */
2873 point++;
2874 }
2875 if (buf)
2876 {
2877 ppc->wType = type;
2878 ppc->cpfx = cpfx;
2879 }
2880 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2881 }
2882 if (buf)
2883 pph->cb = needed - pph_start;
2884 }
2885 return needed;
2886 }
2887
2888 static INT
2889 IntRequestFontSize(PDC dc, FT_Face face, LONG Width, LONG Height)
2890 {
2891 FT_Size_RequestRec req;
2892
2893 if (Width < 0)
2894 Width = -Width;
2895
2896 if (Height < 0)
2897 {
2898 Height = -Height;
2899 }
2900 if (Height == 0)
2901 {
2902 Height = dc->ppdev->devinfo.lfDefaultFont.lfHeight;
2903 }
2904 if (Height == 0)
2905 {
2906 Height = Width;
2907 }
2908
2909 if (Height < 1)
2910 Height = 1;
2911
2912 if (Width > 0xFFFFU)
2913 Width = 0xFFFFU;
2914 if (Height > 0xFFFFU)
2915 Height = 0xFFFFU;
2916
2917 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
2918 req.width = (FT_Long)(Width << 6);
2919 req.height = (FT_Long)(Height << 6);
2920 req.horiResolution = 0;
2921 req.vertResolution = 0;
2922 return FT_Request_Size(face, &req);
2923 }
2924
2925 BOOL
2926 FASTCALL
2927 TextIntUpdateSize(PDC dc,
2928 PTEXTOBJ TextObj,
2929 PFONTGDI FontGDI,
2930 BOOL bDoLock)
2931 {
2932 FT_Face face;
2933 INT error, n;
2934 FT_CharMap charmap, found;
2935 LOGFONTW *plf;
2936
2937 if (bDoLock)
2938 IntLockFreeType;
2939
2940 face = FontGDI->SharedFace->Face;
2941 if (face->charmap == NULL)
2942 {
2943 DPRINT("WARNING: No charmap selected!\n");
2944 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2945
2946 found = NULL;
2947 for (n = 0; n < face->num_charmaps; n++)
2948 {
2949 charmap = face->charmaps[n];
2950 DPRINT("Found charmap encoding: %i\n", charmap->encoding);
2951 if (charmap->encoding != 0)
2952 {
2953 found = charmap;
2954 break;
2955 }
2956 }
2957 if (!found)
2958 {
2959 DPRINT1("WARNING: Could not find desired charmap!\n");
2960 }
2961 else
2962 {
2963 error = FT_Set_Charmap(face, found);
2964 if (error)
2965 {
2966 DPRINT1("WARNING: Could not set the charmap!\n");
2967 }
2968 }
2969 }
2970
2971 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
2972
2973 error = IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
2974
2975 if (bDoLock)
2976 IntUnLockFreeType;
2977
2978 if (error)
2979 {
2980 DPRINT1("Error in setting pixel sizes: %d\n", error);
2981 return FALSE;
2982 }
2983
2984 return TRUE;
2985 }
2986
2987
2988 /*
2989 * Based on WineEngGetGlyphOutline
2990 *
2991 */
2992 ULONG
2993 FASTCALL
2994 ftGdiGetGlyphOutline(
2995 PDC dc,
2996 WCHAR wch,
2997 UINT iFormat,
2998 LPGLYPHMETRICS pgm,
2999 ULONG cjBuf,
3000 PVOID pvBuf,
3001 LPMAT2 pmat2,
3002 BOOL bIgnoreRotation)
3003 {
3004 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3005 PDC_ATTR pdcattr;
3006 PTEXTOBJ TextObj;
3007 PFONTGDI FontGDI;
3008 HFONT hFont = 0;
3009 GLYPHMETRICS gm;
3010 ULONG Size;
3011 FT_Face ft_face;
3012 FT_UInt glyph_index;
3013 DWORD width, height, pitch, needed = 0;
3014 FT_Bitmap ft_bitmap;
3015 FT_Error error;
3016 INT left, right, top = 0, bottom = 0;
3017 FT_Angle angle = 0;
3018 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3019 FLOAT eM11, widthRatio = 1.0;
3020 FT_Matrix transMat = identityMat;
3021 BOOL needsTransform = FALSE;
3022 INT orientation;
3023 LONG aveWidth;
3024 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3025 OUTLINETEXTMETRICW *potm;
3026 XFORM xForm;
3027 LOGFONTW *plf;
3028
3029 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3030 cjBuf, pvBuf, pmat2);
3031
3032 pdcattr = dc->pdcattr;
3033
3034 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
3035 eM11 = xForm.eM11;
3036
3037 hFont = pdcattr->hlfntNew;
3038 TextObj = RealizeFontInit(hFont);
3039
3040 if (!TextObj)
3041 {
3042 EngSetLastError(ERROR_INVALID_HANDLE);
3043 return GDI_ERROR;
3044 }
3045 FontGDI = ObjToGDI(TextObj->Font, FONT);
3046 ft_face = FontGDI->SharedFace->Face;
3047
3048 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3049 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3050 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3051
3052 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3053 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3054 if (!potm)
3055 {
3056 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3057 TEXTOBJ_UnlockText(TextObj);
3058 return GDI_ERROR;
3059 }
3060 IntGetOutlineTextMetrics(FontGDI, Size, potm);
3061
3062 IntLockFreeType;
3063 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3064 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
3065
3066 TEXTOBJ_UnlockText(TextObj);
3067
3068 if (iFormat & GGO_GLYPH_INDEX)
3069 {
3070 glyph_index = wch;
3071 iFormat &= ~GGO_GLYPH_INDEX;
3072 }
3073 else glyph_index = FT_Get_Char_Index(ft_face, wch);
3074
3075 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3076 load_flags |= FT_LOAD_NO_BITMAP;
3077
3078 if (iFormat & GGO_UNHINTED)
3079 {
3080 load_flags |= FT_LOAD_NO_HINTING;
3081 iFormat &= ~GGO_UNHINTED;
3082 }
3083
3084 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3085 if (error)
3086 {
3087 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3088 IntUnLockFreeType;
3089 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3090 return GDI_ERROR;
3091 }
3092 IntUnLockFreeType;
3093
3094 if (aveWidth && potm)
3095 {
3096 widthRatio = (FLOAT)aveWidth * eM11 /
3097 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
3098 }
3099
3100 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3101 right = (INT)((ft_face->glyph->metrics.horiBearingX +
3102 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3103
3104 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3105 lsb = left >> 6;
3106 bbx = (right - left) >> 6;
3107
3108 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3109
3110 IntLockFreeType;
3111
3112 /* Scaling transform */
3113 /*if (aveWidth)*/
3114 {
3115
3116 FT_Matrix ftmatrix;
3117 FLOATOBJ efTemp;
3118
3119 PMATRIX pmx = DC_pmxWorldToDevice(dc);
3120
3121 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3122 efTemp = pmx->efM11;
3123 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3124 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
3125
3126 efTemp = pmx->efM12;
3127 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3128 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
3129
3130 efTemp = pmx->efM21;
3131 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3132 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
3133
3134 efTemp = pmx->efM22;
3135 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3136 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
3137
3138 FT_Matrix_Multiply(&ftmatrix, &transMat);