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