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