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