[WIN32SS] Count number of faces added instead of fonts in IntGdiLoadFontsFromMemory.
[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 FaceCount = 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 ++FaceCount;
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 FaceCount += 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 /* Do not count charsets towards 'faces' loaded */
1046 IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
1047 }
1048 }
1049
1050 return FaceCount; /* number of loaded faces */
1051 }
1052
1053 /*
1054 * IntGdiAddFontResource
1055 *
1056 * Adds the font resource from the specified file to the system.
1057 */
1058
1059 INT FASTCALL
1060 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
1061 {
1062 NTSTATUS Status;
1063 HANDLE FileHandle;
1064 PVOID Buffer = NULL;
1065 IO_STATUS_BLOCK Iosb;
1066 PVOID SectionObject;
1067 ULONG ViewSize = 0;
1068 LARGE_INTEGER SectionSize;
1069 OBJECT_ATTRIBUTES ObjectAttributes;
1070 GDI_LOAD_FONT LoadFont;
1071 INT FontCount;
1072 HANDLE KeyHandle;
1073 static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
1074
1075 /* Open the font file */
1076 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
1077 Status = ZwOpenFile(
1078 &FileHandle,
1079 FILE_GENERIC_READ | SYNCHRONIZE,
1080 &ObjectAttributes,
1081 &Iosb,
1082 FILE_SHARE_READ,
1083 FILE_SYNCHRONOUS_IO_NONALERT);
1084 if (!NT_SUCCESS(Status))
1085 {
1086 DPRINT("Could not load font file: %wZ\n", FileName);
1087 return 0;
1088 }
1089
1090 SectionSize.QuadPart = 0LL;
1091 Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
1092 NULL, &SectionSize, PAGE_READONLY,
1093 SEC_COMMIT, FileHandle, NULL);
1094 if (!NT_SUCCESS(Status))
1095 {
1096 DPRINT("Could not map file: %wZ\n", FileName);
1097 ZwClose(FileHandle);
1098 return 0;
1099 }
1100 ZwClose(FileHandle);
1101
1102 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
1103 if (!NT_SUCCESS(Status))
1104 {
1105 DPRINT("Could not map file: %wZ\n", FileName);
1106 ObDereferenceObject(SectionObject);
1107 return 0;
1108 }
1109
1110 LoadFont.pFileName = FileName;
1111 LoadFont.Memory = SharedMem_Create(Buffer, ViewSize, TRUE);
1112 LoadFont.Characteristics = Characteristics;
1113 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1114 LoadFont.IsTrueType = FALSE;
1115 LoadFont.PrivateEntry = NULL;
1116 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1117
1118 ObDereferenceObject(SectionObject);
1119
1120 /* Release our copy */
1121 IntLockFreeType;
1122 SharedMem_Release(LoadFont.Memory);
1123 IntUnLockFreeType;
1124
1125 if (FontCount > 0)
1126 {
1127 if (LoadFont.IsTrueType)
1128 {
1129 /* append " (TrueType)" */
1130 UNICODE_STRING NewString;
1131 USHORT Length;
1132
1133 Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length;
1134 NewString.Length = 0;
1135 NewString.MaximumLength = Length + sizeof(WCHAR);
1136 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1137 NewString.MaximumLength,
1138 TAG_USTR);
1139 NewString.Buffer[0] = UNICODE_NULL;
1140
1141 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
1142 RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
1143 RtlFreeUnicodeString(&LoadFont.RegValueName);
1144 LoadFont.RegValueName = NewString;
1145 }
1146
1147 /* registry */
1148 InitializeObjectAttributes(&ObjectAttributes, &FontRegPath,
1149 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1150 NULL, NULL);
1151 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
1152 if (NT_SUCCESS(Status))
1153 {
1154 ULONG DataSize;
1155 LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
1156 if (pFileName)
1157 {
1158 pFileName++;
1159 DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
1160 ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
1161 pFileName, DataSize);
1162 }
1163 ZwClose(KeyHandle);
1164 }
1165 }
1166 RtlFreeUnicodeString(&LoadFont.RegValueName);
1167
1168 return FontCount;
1169 }
1170
1171 HANDLE FASTCALL
1172 IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
1173 {
1174 GDI_LOAD_FONT LoadFont;
1175 FONT_ENTRY_COLL_MEM* EntryCollection;
1176 INT FaceCount;
1177 HANDLE Ret = 0;
1178
1179 PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
1180
1181 if (!BufferCopy)
1182 {
1183 *pNumAdded = 0;
1184 return NULL;
1185 }
1186 memcpy(BufferCopy, Buffer, dwSize);
1187
1188 LoadFont.pFileName = NULL;
1189 LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
1190 LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
1191 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1192 LoadFont.IsTrueType = FALSE;
1193 LoadFont.PrivateEntry = NULL;
1194 FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1195
1196 RtlFreeUnicodeString(&LoadFont.RegValueName);
1197
1198 /* Release our copy */
1199 IntLockFreeType;
1200 SharedMem_Release(LoadFont.Memory);
1201 IntUnLockFreeType;
1202
1203 if (FaceCount > 0)
1204 {
1205 EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
1206 if (EntryCollection)
1207 {
1208 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1209 EntryCollection->Entry = LoadFont.PrivateEntry;
1210 IntLockProcessPrivateFonts(Win32Process);
1211 EntryCollection->Handle = ++Win32Process->PrivateMemFontHandleCount;
1212 InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
1213 IntUnLockProcessPrivateFonts(Win32Process);
1214 Ret = (HANDLE)EntryCollection->Handle;
1215 }
1216 }
1217 *pNumAdded = FaceCount;
1218
1219 return Ret;
1220 }
1221
1222 // FIXME: Add RemoveFontResource
1223
1224 static VOID FASTCALL
1225 CleanupFontEntry(PFONT_ENTRY FontEntry)
1226 {
1227 PFONTGDI FontGDI = FontEntry->Font;
1228 PSHARED_FACE SharedFace = FontGDI->SharedFace;
1229
1230 if (FontGDI->Filename)
1231 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1232
1233 EngFreeMem(FontGDI);
1234 SharedFace_Release(SharedFace);
1235 ExFreePoolWithTag(FontEntry, TAG_FONT);
1236 }
1237
1238 VOID FASTCALL
1239 IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
1240 {
1241 PLIST_ENTRY Entry;
1242 PFONT_ENTRY_MEM FontEntry;
1243
1244 while (!IsListEmpty(&Head->ListEntry))
1245 {
1246 Entry = RemoveHeadList(&Head->ListEntry);
1247 FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
1248
1249 CleanupFontEntry(FontEntry->Entry);
1250 ExFreePoolWithTag(FontEntry, TAG_FONT);
1251 }
1252
1253 CleanupFontEntry(Head->Entry);
1254 ExFreePoolWithTag(Head, TAG_FONT);
1255 }
1256
1257 static VOID FASTCALL
1258 UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)
1259 {
1260 PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
1261 PLIST_ENTRY ListEntry;
1262 RemoveEntryList(&Collection->ListEntry);
1263
1264 do {
1265 /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
1266 RemoveEntryList(&FontMemEntry->Entry->ListEntry);
1267
1268 ListEntry = FontMemEntry->ListEntry.Flink;
1269 FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
1270
1271 } while (FontMemEntry != Collection->Entry);
1272 }
1273
1274 BOOL FASTCALL
1275 IntGdiRemoveFontMemResource(HANDLE hMMFont)
1276 {
1277 PLIST_ENTRY Entry;
1278 PFONT_ENTRY_COLL_MEM CurrentEntry;
1279 PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
1280 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1281
1282 IntLockProcessPrivateFonts(Win32Process);
1283 Entry = Win32Process->PrivateMemFontListHead.Flink;
1284 while (Entry != &Win32Process->PrivateMemFontListHead)
1285 {
1286 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1287
1288 if (CurrentEntry->Handle == (UINT)hMMFont)
1289 {
1290 EntryCollection = CurrentEntry;
1291 UnlinkFontMemCollection(CurrentEntry);
1292 break;
1293 }
1294
1295 Entry = Entry->Flink;
1296 }
1297 IntUnLockProcessPrivateFonts(Win32Process);
1298
1299 if (EntryCollection)
1300 {
1301 IntGdiCleanupMemEntry(EntryCollection->Entry);
1302 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1303 return TRUE;
1304 }
1305 return FALSE;
1306 }
1307
1308
1309 VOID FASTCALL
1310 IntGdiCleanupPrivateFontsForProcess(VOID)
1311 {
1312 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1313 PLIST_ENTRY Entry;
1314 PFONT_ENTRY_COLL_MEM EntryCollection;
1315
1316 DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
1317 do {
1318 Entry = NULL;
1319 EntryCollection = NULL;
1320
1321 IntLockProcessPrivateFonts(Win32Process);
1322 if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
1323 {
1324 Entry = Win32Process->PrivateMemFontListHead.Flink;
1325 EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1326 UnlinkFontMemCollection(EntryCollection);
1327 }
1328 IntUnLockProcessPrivateFonts(Win32Process);
1329
1330 if (EntryCollection)
1331 {
1332 IntGdiCleanupMemEntry(EntryCollection->Entry);
1333 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1334 }
1335 else
1336 {
1337 /* No Mem fonts anymore, see if we have any other private fonts left */
1338 Entry = NULL;
1339 IntLockProcessPrivateFonts(Win32Process);
1340 if (!IsListEmpty(&Win32Process->PrivateFontListHead))
1341 {
1342 Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
1343 }
1344 IntUnLockProcessPrivateFonts(Win32Process);
1345
1346 if (Entry)
1347 {
1348 CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
1349 }
1350 }
1351
1352 } while (Entry);
1353 }
1354
1355 BOOL FASTCALL
1356 IntIsFontRenderingEnabled(VOID)
1357 {
1358 BOOL Ret = RenderingEnabled;
1359 HDC hDC;
1360
1361 hDC = IntGetScreenDC();
1362 if (hDC)
1363 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
1364
1365 return Ret;
1366 }
1367
1368 VOID FASTCALL
1369 IntEnableFontRendering(BOOL Enable)
1370 {
1371 RenderingEnabled = Enable;
1372 }
1373
1374 FT_Render_Mode FASTCALL
1375 IntGetFontRenderMode(LOGFONTW *logfont)
1376 {
1377 switch (logfont->lfQuality)
1378 {
1379 case ANTIALIASED_QUALITY:
1380 case NONANTIALIASED_QUALITY:
1381 return FT_RENDER_MODE_MONO;
1382 case DRAFT_QUALITY:
1383 return FT_RENDER_MODE_LIGHT;
1384 /* case CLEARTYPE_QUALITY:
1385 return FT_RENDER_MODE_LCD; */
1386 }
1387 return FT_RENDER_MODE_NORMAL;
1388 }
1389
1390
1391 NTSTATUS FASTCALL
1392 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
1393 {
1394 PLFONT plfont;
1395 LOGFONTW *plf;
1396
1397 plfont = LFONT_AllocFontWithHandle();
1398 if (!plfont)
1399 {
1400 return STATUS_NO_MEMORY;
1401 }
1402
1403 ExInitializePushLock(&plfont->lock);
1404 *NewFont = plfont->BaseObject.hHmgr;
1405 plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
1406 RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
1407 if (lf->lfEscapement != lf->lfOrientation)
1408 {
1409 /* This should really depend on whether GM_ADVANCED is set */
1410 plf->lfOrientation = plf->lfEscapement;
1411 }
1412 LFONT_UnlockFont(plfont);
1413
1414 return STATUS_SUCCESS;
1415 }
1416
1417 /*************************************************************************
1418 * TranslateCharsetInfo
1419 *
1420 * Fills a CHARSETINFO structure for a character set, code page, or
1421 * font. This allows making the correspondance between different labelings
1422 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
1423 * of the same encoding.
1424 *
1425 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
1426 * only one codepage should be set in *Src.
1427 *
1428 * RETURNS
1429 * TRUE on success, FALSE on failure.
1430 *
1431 */
1432 static BOOLEAN APIENTRY
1433 IntTranslateCharsetInfo(PDWORD Src, /* [in]
1434 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
1435 if flags == TCI_SRCCHARSET: a character set value
1436 if flags == TCI_SRCCODEPAGE: a code page value */
1437 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
1438 DWORD Flags /* [in] determines interpretation of lpSrc */)
1439 {
1440 int Index = 0;
1441
1442 switch (Flags)
1443 {
1444 case TCI_SRCFONTSIG:
1445 while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
1446 {
1447 Index++;
1448 }
1449 break;
1450 case TCI_SRCCODEPAGE:
1451 while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciACP)
1452 {
1453 Index++;
1454 }
1455 break;
1456 case TCI_SRCCHARSET:
1457 while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciCharset)
1458 {
1459 Index++;
1460 }
1461 break;
1462 default:
1463 return FALSE;
1464 }
1465
1466 if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == FontTci[Index].ciCharset)
1467 {
1468 return FALSE;
1469 }
1470
1471 RtlCopyMemory(Cs, &FontTci[Index], sizeof(CHARSETINFO));
1472
1473 return TRUE;
1474 }
1475
1476
1477 static BOOL face_has_symbol_charmap(FT_Face ft_face)
1478 {
1479 int i;
1480
1481 for(i = 0; i < ft_face->num_charmaps; i++)
1482 {
1483 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
1484 return TRUE;
1485 }
1486 return FALSE;
1487 }
1488
1489
1490 static void FASTCALL
1491 FillTMEx(TEXTMETRICW *TM, PFONTGDI FontGDI,
1492 TT_OS2 *pOS2, TT_HoriHeader *pHori,
1493 FT_WinFNT_HeaderRec *pFNT, BOOL RealFont)
1494 {
1495 FT_Fixed XScale, YScale;
1496 int Ascent, Descent;
1497 FT_Face Face = FontGDI->SharedFace->Face;
1498
1499 XScale = Face->size->metrics.x_scale;
1500 YScale = Face->size->metrics.y_scale;
1501
1502 if (pFNT)
1503 {
1504 TM->tmHeight = pFNT->pixel_height;
1505 TM->tmAscent = pFNT->ascent;
1506 TM->tmDescent = TM->tmHeight - TM->tmAscent;
1507 TM->tmInternalLeading = pFNT->internal_leading;
1508 TM->tmExternalLeading = pFNT->external_leading;
1509 TM->tmAveCharWidth = pFNT->avg_width;
1510 TM->tmMaxCharWidth = pFNT->max_width;
1511 TM->tmOverhang = 0;
1512 TM->tmDigitizedAspectX = pFNT->horizontal_resolution;
1513 TM->tmDigitizedAspectY = pFNT->vertical_resolution;
1514 TM->tmFirstChar = pFNT->first_char;
1515 TM->tmLastChar = pFNT->last_char;
1516 TM->tmDefaultChar = pFNT->default_char + pFNT->first_char;
1517 TM->tmBreakChar = pFNT->break_char + pFNT->first_char;
1518 TM->tmPitchAndFamily = pFNT->pitch_and_family;
1519 if (RealFont)
1520 {
1521 TM->tmWeight = FontGDI->OriginalWeight;
1522 TM->tmItalic = FontGDI->OriginalItalic;
1523 TM->tmUnderlined = pFNT->underline;
1524 TM->tmStruckOut = pFNT->strike_out;
1525 TM->tmCharSet = pFNT->charset;
1526 }
1527 else
1528 {
1529 TM->tmWeight = FontGDI->RequestWeight;
1530 TM->tmItalic = FontGDI->RequestItalic;
1531 TM->tmUnderlined = FontGDI->RequestUnderline;
1532 TM->tmStruckOut = FontGDI->RequestStrikeOut;
1533 TM->tmCharSet = FontGDI->CharSet;
1534 }
1535 return;
1536 }
1537
1538 if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
1539 {
1540 Ascent = pHori->Ascender;
1541 Descent = -pHori->Descender;
1542 }
1543 else
1544 {
1545 Ascent = pOS2->usWinAscent;
1546 Descent = pOS2->usWinDescent;
1547 }
1548
1549 #if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */
1550 TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
1551 TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
1552 #else /* This (ros) code was previously affected by a FreeType bug, but it works now */
1553 TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* Units above baseline */
1554 TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* Units below baseline */
1555 #endif
1556 TM->tmInternalLeading = (FT_MulFix(Ascent + Descent - Face->units_per_EM, YScale) + 32) >> 6;
1557
1558 TM->tmHeight = TM->tmAscent + TM->tmDescent;
1559
1560 /* MSDN says:
1561 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1562 */
1563 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
1564 - ((Ascent + Descent)
1565 - (pHori->Ascender - pHori->Descender)),
1566 YScale) + 32) >> 6);
1567
1568 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
1569 if (TM->tmAveCharWidth == 0)
1570 {
1571 TM->tmAveCharWidth = 1;
1572 }
1573
1574 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
1575 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
1576
1577 if (RealFont)
1578 {
1579 TM->tmWeight = FontGDI->OriginalWeight;
1580 }
1581 else
1582 {
1583 if (FontGDI->OriginalWeight != FW_DONTCARE &&
1584 FontGDI->OriginalWeight != FW_NORMAL)
1585 {
1586 TM->tmWeight = FontGDI->OriginalWeight;
1587 }
1588 else
1589 {
1590 TM->tmWeight = FontGDI->RequestWeight;
1591 }
1592 }
1593
1594 TM->tmOverhang = 0;
1595 TM->tmDigitizedAspectX = 96;
1596 TM->tmDigitizedAspectY = 96;
1597 if (face_has_symbol_charmap(Face) ||
1598 (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
1599 {
1600 USHORT cpOEM, cpAnsi;
1601
1602 EngGetCurrentCodePage(&cpOEM, &cpAnsi);
1603 TM->tmFirstChar = 0;
1604 switch(cpAnsi)
1605 {
1606 case 1257: /* Baltic */
1607 TM->tmLastChar = 0xf8fd;
1608 break;
1609 default:
1610 TM->tmLastChar = 0xf0ff;
1611 }
1612 TM->tmBreakChar = 0x20;
1613 TM->tmDefaultChar = 0x1f;
1614 }
1615 else
1616 {
1617 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
1618 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
1619
1620 if(pOS2->usFirstCharIndex <= 1)
1621 TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
1622 else if (pOS2->usFirstCharIndex > 0xff)
1623 TM->tmBreakChar = 0x20;
1624 else
1625 TM->tmBreakChar = pOS2->usFirstCharIndex;
1626 TM->tmDefaultChar = TM->tmBreakChar - 1;
1627 }
1628
1629 if (RealFont)
1630 {
1631 TM->tmItalic = FontGDI->OriginalItalic;
1632 TM->tmUnderlined = FALSE;
1633 TM->tmStruckOut = FALSE;
1634 }
1635 else
1636 {
1637 if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
1638 {
1639 TM->tmItalic = 0xFF;
1640 }
1641 else
1642 {
1643 TM->tmItalic = 0;
1644 }
1645 TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
1646 TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
1647 }
1648
1649 if (!FT_IS_FIXED_WIDTH(Face))
1650 {
1651 switch (pOS2->panose[PAN_PROPORTION_INDEX])
1652 {
1653 case PAN_PROP_MONOSPACED:
1654 TM->tmPitchAndFamily = 0;
1655 break;
1656 default:
1657 TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH;
1658 break;
1659 }
1660 }
1661 else
1662 {
1663 TM->tmPitchAndFamily = 0;
1664 }
1665
1666 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
1667 {
1668 case PAN_FAMILY_SCRIPT:
1669 TM->tmPitchAndFamily |= FF_SCRIPT;
1670 break;
1671 case PAN_FAMILY_DECORATIVE:
1672 TM->tmPitchAndFamily |= FF_DECORATIVE;
1673 break;
1674
1675 case PAN_ANY:
1676 case PAN_NO_FIT:
1677 case PAN_FAMILY_TEXT_DISPLAY:
1678 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
1679 /* Which is clearly not what the panose spec says. */
1680 if (TM->tmPitchAndFamily == 0) /* Fixed */
1681 {
1682 TM->tmPitchAndFamily = FF_MODERN;
1683 }
1684 else
1685 {
1686 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
1687 {
1688 case PAN_ANY:
1689 case PAN_NO_FIT:
1690 default:
1691 TM->tmPitchAndFamily |= FF_DONTCARE;
1692 break;
1693
1694 case PAN_SERIF_COVE:
1695 case PAN_SERIF_OBTUSE_COVE:
1696 case PAN_SERIF_SQUARE_COVE:
1697 case PAN_SERIF_OBTUSE_SQUARE_COVE:
1698 case PAN_SERIF_SQUARE:
1699 case PAN_SERIF_THIN:
1700 case PAN_SERIF_BONE:
1701 case PAN_SERIF_EXAGGERATED:
1702 case PAN_SERIF_TRIANGLE:
1703 TM->tmPitchAndFamily |= FF_ROMAN;
1704 break;
1705
1706 case PAN_SERIF_NORMAL_SANS:
1707 case PAN_SERIF_OBTUSE_SANS:
1708 case PAN_SERIF_PERP_SANS:
1709 case PAN_SERIF_FLARED:
1710 case PAN_SERIF_ROUNDED:
1711 TM->tmPitchAndFamily |= FF_SWISS;
1712 break;
1713 }
1714 }
1715 break;
1716 default:
1717 TM->tmPitchAndFamily |= FF_DONTCARE;
1718 }
1719
1720 if (FT_IS_SCALABLE(Face))
1721 {
1722 TM->tmPitchAndFamily |= TMPF_VECTOR;
1723 }
1724 if (FT_IS_SFNT(Face))
1725 {
1726 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
1727 }
1728
1729 TM->tmCharSet = FontGDI->CharSet;
1730 }
1731
1732 static void FASTCALL
1733 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
1734 TT_OS2 *pOS2, TT_HoriHeader *pHori,
1735 FT_WinFNT_HeaderRec *pFNT)
1736 {
1737 FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
1738 }
1739
1740 /*************************************************************
1741 * IntGetOutlineTextMetrics
1742 *
1743 */
1744 INT FASTCALL
1745 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
1746 UINT Size,
1747 OUTLINETEXTMETRICW *Otm)
1748 {
1749 unsigned Needed;
1750 TT_OS2 *pOS2;
1751 TT_HoriHeader *pHori;
1752 TT_Postscript *pPost;
1753 FT_Fixed XScale, YScale;
1754 ANSI_STRING FamilyNameA, StyleNameA;
1755 UNICODE_STRING FamilyNameW, StyleNameW, Regular;
1756 FT_WinFNT_HeaderRec Win;
1757 FT_Error Error;
1758 char *Cp;
1759 NTSTATUS status;
1760 FT_Face Face = FontGDI->SharedFace->Face;
1761
1762 Needed = sizeof(OUTLINETEXTMETRICW);
1763
1764 RtlInitAnsiString(&FamilyNameA, Face->family_name);
1765 status = RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
1766 if (!NT_SUCCESS(status))
1767 {
1768 return 0;
1769 }
1770
1771 RtlInitAnsiString(&StyleNameA, Face->style_name);
1772 status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
1773 if (!NT_SUCCESS(status))
1774 {
1775 RtlFreeUnicodeString(&FamilyNameW);
1776 return 0;
1777 }
1778
1779 /* These names should be read from the TT name table */
1780
1781 /* Length of otmpFamilyName */
1782 Needed += FamilyNameW.Length + sizeof(WCHAR);
1783
1784 RtlInitUnicodeString(&Regular, L"Regular");
1785 /* Length of otmpFaceName */
1786 if (RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
1787 {
1788 Needed += FamilyNameW.Length + sizeof(WCHAR); /* Just the family name */
1789 }
1790 else
1791 {
1792 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
1793 }
1794
1795 /* Length of otmpStyleName */
1796 Needed += StyleNameW.Length + sizeof(WCHAR);
1797
1798 /* Length of otmpFullName */
1799 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
1800
1801 if (Size < Needed)
1802 {
1803 RtlFreeUnicodeString(&FamilyNameW);
1804 RtlFreeUnicodeString(&StyleNameW);
1805 return Needed;
1806 }
1807
1808 XScale = Face->size->metrics.x_scale;
1809 YScale = Face->size->metrics.y_scale;
1810
1811 IntLockFreeType;
1812 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
1813 if (NULL == pOS2)
1814 {
1815 IntUnLockFreeType;
1816 DPRINT1("Can't find OS/2 table - not TT font?\n");
1817 RtlFreeUnicodeString(&StyleNameW);
1818 RtlFreeUnicodeString(&FamilyNameW);
1819 return 0;
1820 }
1821
1822 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
1823 if (NULL == pHori)
1824 {
1825 IntUnLockFreeType;
1826 DPRINT1("Can't find HHEA table - not TT font?\n");
1827 RtlFreeUnicodeString(&StyleNameW);
1828 RtlFreeUnicodeString(&FamilyNameW);
1829 return 0;
1830 }
1831
1832 pPost = FT_Get_Sfnt_Table(Face, ft_sfnt_post); /* We can live with this failing */
1833
1834 Error = FT_Get_WinFNT_Header(Face , &Win);
1835
1836 Otm->otmSize = Needed;
1837
1838 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
1839
1840 Otm->otmFiller = 0;
1841 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1842 Otm->otmfsSelection = pOS2->fsSelection;
1843 Otm->otmfsType = pOS2->fsType;
1844 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1845 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1846 Otm->otmItalicAngle = 0; /* POST table */
1847 Otm->otmEMSquare = Face->units_per_EM;
1848 Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
1849 Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
1850 Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
1851 Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
1852 Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
1853 Otm->otmrcFontBox.left = (FT_MulFix(Face->bbox.xMin, XScale) + 32) >> 6;
1854 Otm->otmrcFontBox.right = (FT_MulFix(Face->bbox.xMax, XScale) + 32) >> 6;
1855 Otm->otmrcFontBox.top = (FT_MulFix(Face->bbox.yMax, YScale) + 32) >> 6;
1856 Otm->otmrcFontBox.bottom = (FT_MulFix(Face->bbox.yMin, YScale) + 32) >> 6;
1857 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
1858 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
1859 Otm->otmMacLineGap = Otm->otmLineGap;
1860 Otm->otmusMinimumPPEM = 0; /* TT Header */
1861 Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
1862 Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
1863 Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
1864 Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
1865 Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
1866 Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
1867 Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
1868 Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
1869 Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
1870 Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
1871 if (!pPost)
1872 {
1873 Otm->otmsUnderscoreSize = 0;
1874 Otm->otmsUnderscorePosition = 0;
1875 }
1876 else
1877 {
1878 Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
1879 Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
1880 }
1881
1882 IntUnLockFreeType;
1883
1884 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1885 Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
1886 Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
1887 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1888 Cp += FamilyNameW.Length + sizeof(WCHAR);
1889 Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
1890 wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
1891 Cp += StyleNameW.Length + sizeof(WCHAR);
1892 Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
1893 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1894 if (!RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
1895 {
1896 wcscat((WCHAR*) Cp, L" ");
1897 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
1898 Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
1899 }
1900 else
1901 {
1902 Cp += FamilyNameW.Length + sizeof(WCHAR);
1903 }
1904 Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
1905 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1906 wcscat((WCHAR*) Cp, L" ");
1907 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
1908
1909 RtlFreeUnicodeString(&StyleNameW);
1910 RtlFreeUnicodeString(&FamilyNameW);
1911
1912 return Needed;
1913 }
1914
1915 static PFONTGDI FASTCALL
1916 FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
1917 {
1918 PLIST_ENTRY Entry;
1919 PFONT_ENTRY CurrentEntry;
1920 ANSI_STRING EntryFaceNameA;
1921 UNICODE_STRING EntryFaceNameW;
1922 FONTGDI *FontGDI;
1923 NTSTATUS status;
1924
1925 Entry = Head->Flink;
1926 while (Entry != Head)
1927 {
1928 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1929
1930 FontGDI = CurrentEntry->Font;
1931 ASSERT(FontGDI);
1932
1933 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
1934 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
1935 if (!NT_SUCCESS(status))
1936 {
1937 break;
1938 }
1939
1940 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
1941 {
1942 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
1943 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
1944 }
1945
1946 if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE))
1947 {
1948 RtlFreeUnicodeString(&EntryFaceNameW);
1949 return FontGDI;
1950 }
1951
1952 RtlFreeUnicodeString(&EntryFaceNameW);
1953 Entry = Entry->Flink;
1954 }
1955
1956 return NULL;
1957 }
1958
1959 static PFONTGDI FASTCALL
1960 FindFaceNameInLists(PUNICODE_STRING FaceName)
1961 {
1962 PPROCESSINFO Win32Process;
1963 PFONTGDI Font;
1964
1965 /* Search the process local list.
1966 We do not have to search the 'Mem' list, since those fonts are linked in the PrivateFontListHead */
1967 Win32Process = PsGetCurrentProcessWin32Process();
1968 IntLockProcessPrivateFonts(Win32Process);
1969 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
1970 IntUnLockProcessPrivateFonts(Win32Process);
1971 if (NULL != Font)
1972 {
1973 return Font;
1974 }
1975
1976 /* Search the global list */
1977 IntLockGlobalFonts;
1978 Font = FindFaceNameInList(FaceName, &FontListHead);
1979 IntUnLockGlobalFonts;
1980
1981 return Font;
1982 }
1983
1984 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
1985 static BYTE
1986 CharSetFromLangID(LANGID LangID)
1987 {
1988 /* FIXME: Add more and fix if wrong */
1989 switch (PRIMARYLANGID(LangID))
1990 {
1991 case LANG_CHINESE:
1992 switch (SUBLANGID(LangID))
1993 {
1994 case SUBLANG_CHINESE_TRADITIONAL:
1995 return CHINESEBIG5_CHARSET;
1996 case SUBLANG_CHINESE_SIMPLIFIED:
1997 default:
1998 break;
1999 }
2000 return GB2312_CHARSET;
2001
2002 case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
2003 case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
2004 return EASTEUROPE_CHARSET;
2005
2006 case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
2007 case LANG_SERBIAN: case LANG_UKRAINIAN:
2008 return RUSSIAN_CHARSET;
2009
2010 case LANG_ARABIC: return ARABIC_CHARSET;
2011 case LANG_GREEK: return GREEK_CHARSET;
2012 case LANG_HEBREW: return HEBREW_CHARSET;
2013 case LANG_JAPANESE: return SHIFTJIS_CHARSET;
2014 case LANG_KOREAN: return JOHAB_CHARSET;
2015 case LANG_TURKISH: return TURKISH_CHARSET;
2016 case LANG_THAI: return THAI_CHARSET;
2017 case LANG_LATVIAN: return BALTIC_CHARSET;
2018 case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
2019
2020 case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
2021 case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
2022 case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
2023 case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
2024 case LANG_SWEDISH: default:
2025 return ANSI_CHARSET;
2026 }
2027 }
2028
2029 static void
2030 SwapEndian(LPVOID pvData, DWORD Size)
2031 {
2032 BYTE b, *pb = pvData;
2033 Size /= 2;
2034 while (Size-- > 0)
2035 {
2036 b = pb[0];
2037 pb[0] = pb[1];
2038 pb[1] = b;
2039 ++pb; ++pb;
2040 }
2041 }
2042
2043 static NTSTATUS
2044 IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face)
2045 {
2046 FT_SfntName Name;
2047 INT i, Count;
2048 WCHAR Buf[LF_FACESIZE];
2049 NTSTATUS Status = STATUS_NOT_FOUND;
2050
2051 RtlInitUnicodeString(pLocalNameW, NULL);
2052
2053 Count = FT_Get_Sfnt_Name_Count(Face);
2054 for (i = 0; i < Count; ++i)
2055 {
2056 FT_Get_Sfnt_Name(Face, i, &Name);
2057 if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
2058 Name.encoding_id != TT_MS_ID_UNICODE_CS)
2059 {
2060 continue; /* not Microsoft Unicode name */
2061 }
2062
2063 if (Name.name_id != TT_NAME_ID_FONT_FAMILY ||
2064 Name.string == NULL || Name.string_len == 0 ||
2065 (Name.string[0] == 0 && Name.string[1] == 0))
2066 {
2067 continue; /* not family name */
2068 }
2069
2070 if (sizeof(Buf) < Name.string_len + sizeof(UNICODE_NULL))
2071 {
2072 continue; /* name too long */
2073 }
2074
2075 /* NOTE: Name.string is not null-terminated */
2076 RtlCopyMemory(Buf, Name.string, Name.string_len);
2077 Buf[Name.string_len / sizeof(WCHAR)] = UNICODE_NULL;
2078
2079 /* Convert UTF-16 big endian to little endian */
2080 SwapEndian(Buf, Name.string_len);
2081 #if 0
2082 DPRINT("IntGetFontLocalizedName: %S (%d)\n", Buf, Name.string_len);
2083 #endif
2084
2085 Status = RtlCreateUnicodeString(pLocalNameW, Buf);
2086 break;
2087 }
2088
2089 return Status;
2090 }
2091
2092 static void FASTCALL
2093 FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
2094 {
2095 ANSI_STRING StyleA;
2096 UNICODE_STRING StyleW;
2097 TT_OS2 *pOS2;
2098 FONTSIGNATURE fs;
2099 CHARSETINFO CharSetInfo;
2100 unsigned i, Size;
2101 OUTLINETEXTMETRICW *Otm;
2102 LOGFONTW *Lf;
2103 TEXTMETRICW *TM;
2104 NEWTEXTMETRICW *Ntm;
2105 DWORD fs0;
2106 NTSTATUS status;
2107 FT_Face Face = FontGDI->SharedFace->Face;
2108
2109 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
2110 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2111 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2112 if (!Otm)
2113 {
2114 return;
2115 }
2116 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2117
2118 Lf = &Info->EnumLogFontEx.elfLogFont;
2119 TM = &Otm->otmTextMetrics;
2120
2121 Lf->lfHeight = TM->tmHeight;
2122 Lf->lfWidth = TM->tmAveCharWidth;
2123 Lf->lfWeight = TM->tmWeight;
2124 Lf->lfItalic = TM->tmItalic;
2125 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
2126 Lf->lfCharSet = TM->tmCharSet;
2127 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
2128 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
2129 Lf->lfQuality = PROOF_QUALITY;
2130
2131 Ntm = &Info->NewTextMetricEx.ntmTm;
2132 Ntm->tmHeight = TM->tmHeight;
2133 Ntm->tmAscent = TM->tmAscent;
2134 Ntm->tmDescent = TM->tmDescent;
2135 Ntm->tmInternalLeading = TM->tmInternalLeading;
2136 Ntm->tmExternalLeading = TM->tmExternalLeading;
2137 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
2138 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
2139 Ntm->tmWeight = TM->tmWeight;
2140 Ntm->tmOverhang = TM->tmOverhang;
2141 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
2142 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
2143 Ntm->tmFirstChar = TM->tmFirstChar;
2144 Ntm->tmLastChar = TM->tmLastChar;
2145 Ntm->tmDefaultChar = TM->tmDefaultChar;
2146 Ntm->tmBreakChar = TM->tmBreakChar;
2147 Ntm->tmItalic = TM->tmItalic;
2148 Ntm->tmUnderlined = TM->tmUnderlined;
2149 Ntm->tmStruckOut = TM->tmStruckOut;
2150 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
2151 Ntm->tmCharSet = TM->tmCharSet;
2152 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
2153
2154 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
2155
2156 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
2157
2158 Ntm->ntmSizeEM = Otm->otmEMSquare;
2159 Ntm->ntmCellHeight = Otm->otmEMSquare;
2160 Ntm->ntmAvgWidth = 0;
2161
2162 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
2163 ? TRUETYPE_FONTTYPE : 0);
2164
2165 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
2166 Info->FontType |= RASTER_FONTTYPE;
2167
2168 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2169
2170 /* try the localized name */
2171 status = STATUS_UNSUCCESSFUL;
2172 if (CharSetFromLangID(gusLanguageID) == FontGDI->CharSet)
2173 {
2174 /* get localized name */
2175 UNICODE_STRING LocalNameW;
2176 status = IntGetFontLocalizedName(&LocalNameW, Face);
2177 if (NT_SUCCESS(status))
2178 {
2179 /* store it */
2180 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
2181 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
2182 LocalNameW.Buffer);
2183 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2184 sizeof(Info->EnumLogFontEx.elfFullName),
2185 LocalNameW.Buffer);
2186 }
2187 RtlFreeUnicodeString(&LocalNameW);
2188 }
2189
2190 /* if localized name was unavailable */
2191 if (!NT_SUCCESS(status))
2192 {
2193 /* store English name */
2194 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
2195 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
2196 FaceName);
2197 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2198 sizeof(Info->EnumLogFontEx.elfFullName),
2199 FaceName);
2200 }
2201
2202 RtlInitAnsiString(&StyleA, Face->style_name);
2203 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
2204 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
2205 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
2206 if (!NT_SUCCESS(status))
2207 {
2208 return;
2209 }
2210 if (StyleW.Length)
2211 {
2212 if (wcslen(Info->EnumLogFontEx.elfFullName) +
2213 StyleW.Length / sizeof(WCHAR) + 1 <=
2214 sizeof(Info->EnumLogFontEx.elfFullName))
2215 {
2216 wcscat(Info->EnumLogFontEx.elfFullName, L" ");
2217 wcscat(Info->EnumLogFontEx.elfFullName, StyleW.Buffer);
2218 }
2219 }
2220
2221 Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
2222 Info->EnumLogFontEx.elfScript[0] = L'\0';
2223 IntLockFreeType;
2224 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2225
2226 if (!pOS2)
2227 {
2228 IntUnLockFreeType;
2229 return;
2230 }
2231
2232 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2233 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2234 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2235 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2236 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2237 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2238
2239 if (0 == pOS2->version)
2240 {
2241 FT_UInt Dummy;
2242
2243 if (FT_Get_First_Char(Face, &Dummy) < 0x100)
2244 fs.fsCsb[0] |= FS_LATIN1;
2245 else
2246 fs.fsCsb[0] |= FS_SYMBOL;
2247 }
2248 IntUnLockFreeType;
2249
2250 if (fs.fsCsb[0] == 0)
2251 {
2252 /* Let's see if we can find any interesting cmaps */
2253 for (i = 0; i < (UINT)Face->num_charmaps; i++)
2254 {
2255 switch (Face->charmaps[i]->encoding)
2256 {
2257 case FT_ENCODING_UNICODE:
2258 case FT_ENCODING_APPLE_ROMAN:
2259 fs.fsCsb[0] |= FS_LATIN1;
2260 break;
2261 case FT_ENCODING_MS_SYMBOL:
2262 fs.fsCsb[0] |= FS_SYMBOL;
2263 break;
2264 default:
2265 break;
2266 }
2267 }
2268 }
2269
2270 for (i = 0; i < MAXTCIINDEX; i++)
2271 {
2272 fs0 = 1L << i;
2273 if (fs.fsCsb[0] & fs0)
2274 {
2275 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
2276 {
2277 CharSetInfo.ciCharset = DEFAULT_CHARSET;
2278 }
2279 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
2280 {
2281 Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
2282 if (ElfScripts[i])
2283 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
2284 else
2285 {
2286 DPRINT1("Unknown elfscript for bit %u\n", i);
2287 }
2288 }
2289 }
2290 }
2291 Info->NewTextMetricEx.ntmFontSig = fs;
2292 }
2293
2294 static int FASTCALL
2295 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
2296 {
2297 DWORD i;
2298 UNICODE_STRING InfoFaceName;
2299
2300 for (i = 0; i < InfoEntries; i++)
2301 {
2302 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
2303 if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE))
2304 {
2305 return i;
2306 }
2307 }
2308
2309 return -1;
2310 }
2311
2312 static BOOLEAN FASTCALL
2313 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
2314 PFONTFAMILYINFO Info, DWORD InfoEntries)
2315 {
2316 UNICODE_STRING LogFontFaceName;
2317
2318 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
2319 if (0 != LogFontFaceName.Length &&
2320 !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE))
2321 {
2322 return FALSE;
2323 }
2324
2325 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
2326 }
2327
2328 static BOOLEAN FASTCALL
2329 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
2330 PFONTFAMILYINFO Info,
2331 DWORD *Count,
2332 DWORD Size,
2333 PLIST_ENTRY Head)
2334 {
2335 PLIST_ENTRY Entry;
2336 PFONT_ENTRY CurrentEntry;
2337 ANSI_STRING EntryFaceNameA;
2338 UNICODE_STRING EntryFaceNameW;
2339 FONTGDI *FontGDI;
2340 NTSTATUS status;
2341
2342 Entry = Head->Flink;
2343 while (Entry != Head)
2344 {
2345 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2346
2347 FontGDI = CurrentEntry->Font;
2348 ASSERT(FontGDI);
2349
2350 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
2351 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2352 if (!NT_SUCCESS(status))
2353 {
2354 return FALSE;
2355 }
2356
2357 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2358 {
2359 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2360 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2361 }
2362
2363 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
2364 {
2365 if (*Count < Size)
2366 {
2367 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
2368 }
2369 (*Count)++;
2370 }
2371 RtlFreeUnicodeString(&EntryFaceNameW);
2372 Entry = Entry->Flink;
2373 }
2374
2375 return TRUE;
2376 }
2377
2378 typedef struct FontFamilyInfoCallbackContext
2379 {
2380 LPLOGFONTW LogFont;
2381 PFONTFAMILYINFO Info;
2382 DWORD Count;
2383 DWORD Size;
2384 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
2385
2386 _Function_class_(RTL_QUERY_REGISTRY_ROUTINE)
2387 static NTSTATUS APIENTRY
2388 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
2389 IN PVOID ValueData, IN ULONG ValueLength,
2390 IN PVOID Context, IN PVOID EntryContext)
2391 {
2392 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
2393 UNICODE_STRING RegistryName, RegistryValue;
2394 int Existing;
2395 PFONTGDI FontGDI;
2396
2397 if (REG_SZ != ValueType)
2398 {
2399 return STATUS_SUCCESS;
2400 }
2401 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
2402 RtlInitUnicodeString(&RegistryName, ValueName);
2403
2404 /* Do we need to include this font family? */
2405 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
2406 min(InfoContext->Count, InfoContext->Size)))
2407 {
2408 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
2409 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
2410 min(InfoContext->Count, InfoContext->Size));
2411 if (0 <= Existing)
2412 {
2413 /* We already have the information about the "real" font. Just copy it */
2414 if (InfoContext->Count < InfoContext->Size)
2415 {
2416 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
2417 RtlStringCbCopyNW(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
2418 sizeof(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName),
2419 RegistryName.Buffer,
2420 RegistryName.Length);
2421 }
2422 InfoContext->Count++;
2423 return STATUS_SUCCESS;
2424 }
2425
2426 /* Try to find information about the "real" font */
2427 FontGDI = FindFaceNameInLists(&RegistryValue);
2428 if (NULL == FontGDI)
2429 {
2430 /* "Real" font not found, discard this registry entry */
2431 return STATUS_SUCCESS;
2432 }
2433
2434 /* Return info about the "real" font but with the name of the alias */
2435 if (InfoContext->Count < InfoContext->Size)
2436 {
2437 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
2438 RegistryName.Buffer, FontGDI);
2439 }
2440 InfoContext->Count++;
2441 return STATUS_SUCCESS;
2442 }
2443
2444 return STATUS_SUCCESS;
2445 }
2446
2447 static BOOLEAN FASTCALL
2448 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
2449 PFONTFAMILYINFO Info,
2450 DWORD *Count,
2451 DWORD Size)
2452 {
2453 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2454 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
2455 NTSTATUS Status;
2456
2457 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
2458 The real work is done in the registry callback function */
2459 Context.LogFont = LogFont;
2460 Context.Info = Info;
2461 Context.Count = *Count;
2462 Context.Size = Size;
2463
2464 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
2465 QueryTable[0].Flags = 0;
2466 QueryTable[0].Name = NULL;
2467 QueryTable[0].EntryContext = NULL;
2468 QueryTable[0].DefaultType = REG_NONE;
2469 QueryTable[0].DefaultData = NULL;
2470 QueryTable[0].DefaultLength = 0;
2471
2472 QueryTable[1].QueryRoutine = NULL;
2473 QueryTable[1].Name = NULL;
2474
2475 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2476 L"FontSubstitutes",
2477 QueryTable,
2478 &Context,
2479 NULL);
2480 if (NT_SUCCESS(Status))
2481 {
2482 *Count = Context.Count;
2483 }
2484
2485 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
2486 }
2487
2488 BOOL
2489 FASTCALL
2490 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
2491 {
2492 if ( lprs )
2493 {
2494 lprs->nSize = sizeof(RASTERIZER_STATUS);
2495 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
2496 lprs->nLanguageID = gusLanguageID;
2497 return TRUE;
2498 }
2499 EngSetLastError(ERROR_INVALID_PARAMETER);
2500 return FALSE;
2501 }
2502
2503 static
2504 BOOL
2505 SameScaleMatrix(
2506 PMATRIX pmx1,
2507 PMATRIX pmx2)
2508 {
2509 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
2510 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
2511 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
2512 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
2513 }
2514
2515 FT_BitmapGlyph APIENTRY
2516 ftGdiGlyphCacheGet(
2517 FT_Face Face,
2518 INT GlyphIndex,
2519 INT Height,
2520 PMATRIX pmx)
2521 {
2522 PLIST_ENTRY CurrentEntry;
2523 PFONT_CACHE_ENTRY FontEntry;
2524
2525 ASSERT_FREETYPE_LOCK_HELD();
2526
2527 CurrentEntry = FontCacheListHead.Flink;
2528 while (CurrentEntry != &FontCacheListHead)
2529 {
2530 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
2531 if ((FontEntry->Face == Face) &&
2532 (FontEntry->GlyphIndex == GlyphIndex) &&
2533 (FontEntry->Height == Height) &&
2534 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2535 break;
2536 CurrentEntry = CurrentEntry->Flink;
2537 }
2538
2539 if (CurrentEntry == &FontCacheListHead)
2540 {
2541 return NULL;
2542 }
2543
2544 RemoveEntryList(CurrentEntry);
2545 InsertHeadList(&FontCacheListHead, CurrentEntry);
2546 return FontEntry->BitmapGlyph;
2547 }
2548
2549 /* no cache */
2550 FT_BitmapGlyph APIENTRY
2551 ftGdiGlyphSet(
2552 FT_Face Face,
2553 FT_GlyphSlot GlyphSlot,
2554 FT_Render_Mode RenderMode)
2555 {
2556 FT_Glyph Glyph;
2557 INT error;
2558 FT_Bitmap AlignedBitmap;
2559 FT_BitmapGlyph BitmapGlyph;
2560
2561 error = FT_Get_Glyph(GlyphSlot, &Glyph);
2562 if (error)
2563 {
2564 DPRINT1("Failure getting glyph.\n");
2565 return NULL;
2566 }
2567
2568 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2569 if (error)
2570 {
2571 FT_Done_Glyph(Glyph);
2572 DPRINT1("Failure rendering glyph.\n");
2573 return NULL;
2574 }
2575
2576 BitmapGlyph = (FT_BitmapGlyph)Glyph;
2577 FT_Bitmap_New(&AlignedBitmap);
2578 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2579 {
2580 DPRINT1("Conversion failed\n");
2581 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2582 return NULL;
2583 }
2584
2585 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2586 BitmapGlyph->bitmap = AlignedBitmap;
2587
2588 return BitmapGlyph;
2589 }
2590
2591 FT_BitmapGlyph APIENTRY
2592 ftGdiGlyphCacheSet(
2593 FT_Face Face,
2594 INT GlyphIndex,
2595 INT Height,
2596 PMATRIX pmx,
2597 FT_GlyphSlot GlyphSlot,
2598 FT_Render_Mode RenderMode)
2599 {
2600 FT_Glyph GlyphCopy;
2601 INT error;
2602 PFONT_CACHE_ENTRY NewEntry;
2603 FT_Bitmap AlignedBitmap;
2604 FT_BitmapGlyph BitmapGlyph;
2605
2606 ASSERT_FREETYPE_LOCK_HELD();
2607
2608 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2609 if (error)
2610 {
2611 DPRINT1("Failure caching glyph.\n");
2612 return NULL;
2613 };
2614
2615 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2616 if (error)
2617 {
2618 FT_Done_Glyph(GlyphCopy);
2619 DPRINT1("Failure rendering glyph.\n");
2620 return NULL;
2621 };
2622
2623 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
2624 if (!NewEntry)
2625 {
2626 DPRINT1("Alloc failure caching glyph.\n");
2627 FT_Done_Glyph(GlyphCopy);
2628 return NULL;
2629 }
2630
2631 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2632 FT_Bitmap_New(&AlignedBitmap);
2633 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2634 {
2635 DPRINT1("Conversion failed\n");
2636 ExFreePoolWithTag(NewEntry, TAG_FONT);
2637 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2638 return NULL;
2639 }
2640
2641 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2642 BitmapGlyph->bitmap = AlignedBitmap;
2643
2644 NewEntry->GlyphIndex = GlyphIndex;
2645 NewEntry->Face = Face;
2646 NewEntry->BitmapGlyph = BitmapGlyph;
2647 NewEntry->Height = Height;
2648 NewEntry->mxWorldToDevice = *pmx;
2649
2650 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
2651 if (++FontCacheNumEntries > MAX_FONT_CACHE)
2652 {
2653 NewEntry = CONTAINING_RECORD(FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
2654 RemoveCachedEntry(NewEntry);
2655 }
2656
2657 return BitmapGlyph;
2658 }
2659
2660
2661 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2662 {
2663 pt->x.value = vec->x >> 6;
2664 pt->x.fract = (vec->x & 0x3f) << 10;
2665 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2666 pt->y.value = vec->y >> 6;
2667 pt->y.fract = (vec->y & 0x3f) << 10;
2668 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2669 }
2670
2671 /*
2672 This function builds an FT_Fixed from a float. It puts the integer part
2673 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2674 It fails if the integer part of the float number is greater than SHORT_MAX.
2675 */
2676 static __inline FT_Fixed FT_FixedFromFloat(float f)
2677 {
2678 short value = f;
2679 unsigned short fract = (f - value) * 0xFFFF;
2680 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2681 }
2682
2683 /*
2684 This function builds an FT_Fixed from a FIXED. It simply put f.value
2685 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2686 */
2687 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2688 {
2689 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2690 }
2691
2692 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2693 {
2694 TTPOLYGONHEADER *pph;
2695 TTPOLYCURVE *ppc;
2696 int needed = 0, point = 0, contour, first_pt;
2697 unsigned int pph_start, cpfx;
2698 DWORD type;
2699
2700 for (contour = 0; contour < outline->n_contours; contour++)
2701 {
2702 /* Ignore contours containing one point */
2703 if (point == outline->contours[contour])
2704 {
2705 point++;
2706 continue;
2707 }
2708
2709 pph_start = needed;
2710 pph = (TTPOLYGONHEADER *)(buf + needed);
2711 first_pt = point;
2712 if (buf)
2713 {
2714 pph->dwType = TT_POLYGON_TYPE;
2715 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2716 }
2717 needed += sizeof(*pph);
2718 point++;
2719 while (point <= outline->contours[contour])
2720 {
2721 ppc = (TTPOLYCURVE *)(buf + needed);
2722 type = outline->tags[point] & FT_Curve_Tag_On ?
2723 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2724 cpfx = 0;
2725 do
2726 {
2727 if (buf)
2728 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2729 cpfx++;
2730 point++;
2731 } while (point <= outline->contours[contour] &&
2732 (outline->tags[point] & FT_Curve_Tag_On) ==
2733 (outline->tags[point-1] & FT_Curve_Tag_On));
2734 /* At the end of a contour Windows adds the start point, but
2735 only for Beziers */
2736 if (point > outline->contours[contour] &&
2737 !(outline->tags[point-1] & FT_Curve_Tag_On))
2738 {
2739 if (buf)
2740 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2741 cpfx++;
2742 }
2743 else if (point <= outline->contours[contour] &&
2744 outline->tags[point] & FT_Curve_Tag_On)
2745 {
2746 /* add closing pt for bezier */
2747 if (buf)
2748 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2749 cpfx++;
2750 point++;
2751 }
2752 if (buf)
2753 {
2754 ppc->wType = type;
2755 ppc->cpfx = cpfx;
2756 }
2757 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2758 }
2759 if (buf)
2760 pph->cb = needed - pph_start;
2761 }
2762 return needed;
2763 }
2764
2765 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2766 {
2767 /* Convert the quadratic Beziers to cubic Beziers.
2768 The parametric eqn for a cubic Bezier is, from PLRM:
2769 r(t) = at^3 + bt^2 + ct + r0
2770 with the control points:
2771 r1 = r0 + c/3
2772 r2 = r1 + (c + b)/3
2773 r3 = r0 + c + b + a
2774
2775 A quadratic Bezier has the form:
2776 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2777
2778 So equating powers of t leads to:
2779 r1 = 2/3 p1 + 1/3 p0
2780 r2 = 2/3 p1 + 1/3 p2
2781 and of course r0 = p0, r3 = p2
2782 */
2783 int contour, point = 0, first_pt;
2784 TTPOLYGONHEADER *pph;
2785 TTPOLYCURVE *ppc;
2786 DWORD pph_start, cpfx, type;
2787 FT_Vector cubic_control[4];
2788 unsigned int needed = 0;
2789
2790 for (contour = 0; contour < outline->n_contours; contour++)
2791 {
2792 pph_start = needed;
2793 pph = (TTPOLYGONHEADER *)(buf + needed);
2794 first_pt = point;
2795 if (buf)
2796 {
2797 pph->dwType = TT_POLYGON_TYPE;
2798 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2799 }
2800 needed += sizeof(*pph);
2801 point++;
2802 while (point <= outline->contours[contour])
2803 {
2804 ppc = (TTPOLYCURVE *)(buf + needed);
2805 type = outline->tags[point] & FT_Curve_Tag_On ?
2806 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2807 cpfx = 0;
2808 do
2809 {
2810 if (type == TT_PRIM_LINE)
2811 {
2812 if (buf)
2813 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2814 cpfx++;
2815 point++;
2816 }
2817 else
2818 {
2819 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2820 so cpfx = 3n */
2821
2822 /* FIXME: Possible optimization in endpoint calculation
2823 if there are two consecutive curves */
2824 cubic_control[0] = outline->points[point-1];
2825 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2826 {
2827 cubic_control[0].x += outline->points[point].x + 1;
2828 cubic_control[0].y += outline->points[point].y + 1;
2829 cubic_control[0].x >>= 1;
2830 cubic_control[0].y >>= 1;
2831 }
2832 if (point+1 > outline->contours[contour])
2833 cubic_control[3] = outline->points[first_pt];
2834 else
2835 {
2836 cubic_control[3] = outline->points[point+1];
2837 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2838 {
2839 cubic_control[3].x += outline->points[point].x + 1;
2840 cubic_control[3].y += outline->points[point].y + 1;
2841 cubic_control[3].x >>= 1;
2842 cubic_control[3].y >>= 1;
2843 }
2844 }
2845 /* r1 = 1/3 p0 + 2/3 p1
2846 r2 = 1/3 p2 + 2/3 p1 */
2847 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2848 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2849 cubic_control[2] = cubic_control[1];
2850 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2851 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2852 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2853 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2854 if (buf)
2855 {
2856 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2857 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2858 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2859 }
2860 cpfx += 3;
2861 point++;
2862 }
2863 } while (point <= outline->contours[contour] &&
2864 (outline->tags[point] & FT_Curve_Tag_On) ==
2865 (outline->tags[point-1] & FT_Curve_Tag_On));
2866 /* At the end of a contour Windows adds the start point,
2867 but only for Beziers and we've already done that.
2868 */
2869 if (point <= outline->contours[contour] &&
2870 outline->tags[point] & FT_Curve_Tag_On)
2871 {
2872 /* This is the closing pt of a bezier, but we've already
2873 added it, so just inc point and carry on */
2874 point++;
2875 }
2876 if (buf)
2877 {
2878 ppc->wType = type;
2879 ppc->cpfx = cpfx;
2880 }
2881 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2882 }
2883 if (buf)
2884 pph->cb = needed - pph_start;
2885 }
2886 return needed;
2887 }
2888
2889 static INT
2890 IntRequestFontSize(PDC dc, FT_Face face, LONG Width, LONG Height)
2891 {
2892 FT_Size_RequestRec req;
2893
2894 if (Width < 0)
2895 Width = -Width;
2896
2897 if (Height < 0)
2898 {
2899 Height = -Height;
2900 }
2901 if (Height == 0)
2902 {
2903 Height = dc->ppdev->devinfo.lfDefaultFont.lfHeight;
2904 }
2905 if (Height == 0)
2906 {
2907 Height = Width;
2908 }
2909
2910 if (Height < 1)
2911 Height = 1;
2912
2913 if (Width > 0xFFFFU)
2914 Width = 0xFFFFU;
2915 if (Height > 0xFFFFU)
2916 Height = 0xFFFFU;
2917
2918 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
2919 req.width = (FT_Long)(Width << 6);
2920 req.height = (FT_Long)(Height << 6);
2921 req.horiResolution = 0;
2922 req.vertResolution = 0;
2923 return FT_Request_Size(face, &req);
2924 }
2925
2926 BOOL
2927 FASTCALL
2928 TextIntUpdateSize(PDC dc,
2929 PTEXTOBJ TextObj,
2930 PFONTGDI FontGDI,
2931 BOOL bDoLock)
2932 {
2933 FT_Face face;
2934 INT error, n;
2935 FT_CharMap charmap, found;
2936 LOGFONTW *plf;
2937
2938 if (bDoLock)
2939 IntLockFreeType;
2940
2941 face = FontGDI->SharedFace->Face;
2942 if (face->charmap == NULL)
2943 {
2944 DPRINT("WARNING: No charmap selected!\n");
2945 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2946
2947 found = NULL;
2948 for (n = 0; n < face->num_charmaps; n++)
2949 {
2950 charmap = face->charmaps[n];
2951 DPRINT("Found charmap encoding: %i\n", charmap->encoding);
2952 if (charmap->encoding != 0)
2953 {
2954 found = charmap;
2955 break;
2956 }
2957 }
2958 if (!found)
2959 {
2960 DPRINT1("WARNING: Could not find desired charmap!\n");
2961 }
2962 else
2963 {
2964 error = FT_Set_Charmap(face, found);
2965 if (error)
2966 {
2967 DPRINT1("WARNING: Could not set the charmap!\n");
2968 }
2969 }
2970 }
2971
2972 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
2973
2974 error = IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
2975
2976 if (bDoLock)
2977 IntUnLockFreeType;
2978
2979 if (error)
2980 {
2981 DPRINT1("Error in setting pixel sizes: %d\n", error);
2982 return FALSE;
2983 }
2984
2985 return TRUE;
2986 }
2987
2988
2989 /*
2990 * Based on WineEngGetGlyphOutline
2991 *
2992 */
2993 ULONG
2994 FASTCALL
2995 ftGdiGetGlyphOutline(
2996 PDC dc,
2997 WCHAR wch,
2998 UINT iFormat,
2999 LPGLYPHMETRICS pgm,
3000 ULONG cjBuf,
3001 PVOID pvBuf,
3002 LPMAT2 pmat2,
3003 BOOL bIgnoreRotation)
3004 {
3005 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3006 PDC_ATTR pdcattr;
3007 PTEXTOBJ TextObj;
3008 PFONTGDI FontGDI;
3009 HFONT hFont = 0;
3010 GLYPHMETRICS gm;
3011 ULONG Size;
3012 FT_Face ft_face;
3013 FT_UInt glyph_index;
3014 DWORD width, height, pitch, needed = 0;
3015 FT_Bitmap ft_bitmap;
3016 FT_Error error;
3017 INT left, right, top = 0, bottom = 0;
3018 FT_Angle angle = 0;
3019 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3020 FLOAT eM11, widthRatio = 1.0;
3021 FT_Matrix transMat = identityMat;
3022 BOOL needsTransform = FALSE;
3023 INT orientation;
3024 LONG aveWidth;
3025 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3026 OUTLINETEXTMETRICW *potm;
3027 XFORM xForm;
3028 LOGFONTW *plf;
3029
3030 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3031 cjBuf, pvBuf, pmat2);
3032
3033 pdcattr = dc->pdcattr;
3034
3035 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
3036 eM11 = xForm.eM11;
3037
3038 hFont = pdcattr->hlfntNew;
3039 TextObj = RealizeFontInit(hFont);
3040
3041 if (!TextObj)
3042 {
3043 EngSetLastError(ERROR_INVALID_HANDLE);
3044 return GDI_ERROR;
3045 }
3046 FontGDI = ObjToGDI(TextObj->Font, FONT);
3047 ft_face = FontGDI->SharedFace->Face;
3048
3049 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3050 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3051 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3052
3053 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3054 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3055 if (!potm)
3056 {
3057 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3058 TEXTOBJ_UnlockText(TextObj);
3059 return GDI_ERROR;
3060 }
3061 IntGetOutlineTextMetrics(FontGDI, Size, potm);
3062
3063 IntLockFreeType;
3064 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3065 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
3066
3067 TEXTOBJ_UnlockText(TextObj);
3068
3069 if (iFormat & GGO_GLYPH_INDEX)
3070 {
3071 glyph_index = wch;
3072 iFormat &= ~GGO_GLYPH_INDEX;
3073 }
3074 else glyph_index = FT_Get_Char_Index(ft_face, wch);
3075
3076 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3077 load_flags |= FT_LOAD_NO_BITMAP;
3078
3079 if (iFormat & GGO_UNHINTED)
3080 {
3081 load_flags |= FT_LOAD_NO_HINTING;
3082 iFormat &= ~GGO_UNHINTED;
3083 }
3084
3085 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3086 if (error)
3087 {
3088 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3089 IntUnLockFreeType;
3090 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3091 return GDI_ERROR;
3092 }
3093 IntUnLockFreeType;
3094
3095 if (aveWidth && potm)
3096 {
3097 widthRatio = (FLOAT)aveWidth * eM11 /
3098 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
3099 }
3100
3101 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3102 right = (INT)((ft_face->glyph->metrics.horiBearingX +
3103 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3104
3105 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3106 lsb = left >> 6;
3107 bbx = (right - left) >> 6;
3108
3109 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3110
3111 IntLockFreeType;
3112
3113 /* Scaling transform */
3114 /*if (aveWidth)*/
3115 {
3116
3117 FT_Matrix ftmatrix;
3118 FLOATOBJ efTemp;
3119
3120 PMATRIX pmx = DC_pmxWorldToDevice(dc);
3121
3122 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3123 efTemp = pmx->efM11;
3124 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3125 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
3126
3127 efTemp = pmx->efM12;
3128 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3129 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
3130
3131 efTemp = pmx->efM21;
3132 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3133 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
3134
3135 efTemp = pmx->efM22;
3136 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3137 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
3138