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