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