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