[WIN32SS][NTGDI] usWinAscent and usWinDescent must be treated as signed (#1670)
[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 ((FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent == 0)
1872 {
1873 Ascent = pHori->Ascender;
1874 Descent = -pHori->Descender;
1875 }
1876 else
1877 {
1878 Ascent = (FT_Short)pOS2->usWinAscent;
1879 Descent = (FT_Short)pOS2->usWinDescent;
1880 }
1881
1882 TM->tmAscent = FontGDI->tmAscent;
1883 TM->tmDescent = FontGDI->tmDescent;
1884 TM->tmHeight = TM->tmAscent + TM->tmDescent;
1885 TM->tmInternalLeading = FontGDI->tmInternalLeading;
1886
1887 /* MSDN says:
1888 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1889 */
1890 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
1891 - ((Ascent + Descent)
1892 - (pHori->Ascender - pHori->Descender)),
1893 YScale) + 32) >> 6);
1894
1895 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
1896 if (TM->tmAveCharWidth == 0)
1897 {
1898 TM->tmAveCharWidth = 1;
1899 }
1900
1901 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
1902 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
1903
1904 if (RealFont)
1905 {
1906 TM->tmWeight = FontGDI->OriginalWeight;
1907 }
1908 else
1909 {
1910 if (FontGDI->OriginalWeight != FW_DONTCARE &&
1911 FontGDI->OriginalWeight != FW_NORMAL)
1912 {
1913 TM->tmWeight = FontGDI->OriginalWeight;
1914 }
1915 else
1916 {
1917 TM->tmWeight = FontGDI->RequestWeight;
1918 }
1919 }
1920
1921 TM->tmOverhang = 0;
1922 TM->tmDigitizedAspectX = 96;
1923 TM->tmDigitizedAspectY = 96;
1924 if (face_has_symbol_charmap(Face) ||
1925 (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
1926 {
1927 USHORT cpOEM, cpAnsi;
1928
1929 EngGetCurrentCodePage(&cpOEM, &cpAnsi);
1930 TM->tmFirstChar = 0;
1931 switch(cpAnsi)
1932 {
1933 case 1257: /* Baltic */
1934 TM->tmLastChar = 0xf8fd;
1935 break;
1936 default:
1937 TM->tmLastChar = 0xf0ff;
1938 }
1939 TM->tmBreakChar = 0x20;
1940 TM->tmDefaultChar = 0x1f;
1941 }
1942 else
1943 {
1944 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
1945 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
1946
1947 if(pOS2->usFirstCharIndex <= 1)
1948 TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
1949 else if (pOS2->usFirstCharIndex > 0xff)
1950 TM->tmBreakChar = 0x20;
1951 else
1952 TM->tmBreakChar = pOS2->usFirstCharIndex;
1953 TM->tmDefaultChar = TM->tmBreakChar - 1;
1954 }
1955
1956 if (RealFont)
1957 {
1958 TM->tmItalic = FontGDI->OriginalItalic;
1959 TM->tmUnderlined = FALSE;
1960 TM->tmStruckOut = FALSE;
1961 }
1962 else
1963 {
1964 if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
1965 {
1966 TM->tmItalic = 0xFF;
1967 }
1968 else
1969 {
1970 TM->tmItalic = 0;
1971 }
1972 TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
1973 TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
1974 }
1975
1976 if (!FT_IS_FIXED_WIDTH(Face))
1977 {
1978 switch (pOS2->panose[PAN_PROPORTION_INDEX])
1979 {
1980 case PAN_PROP_MONOSPACED:
1981 TM->tmPitchAndFamily = 0;
1982 break;
1983 default:
1984 TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH;
1985 break;
1986 }
1987 }
1988 else
1989 {
1990 TM->tmPitchAndFamily = 0;
1991 }
1992
1993 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
1994 {
1995 case PAN_FAMILY_SCRIPT:
1996 TM->tmPitchAndFamily |= FF_SCRIPT;
1997 break;
1998 case PAN_FAMILY_DECORATIVE:
1999 TM->tmPitchAndFamily |= FF_DECORATIVE;
2000 break;
2001
2002 case PAN_ANY:
2003 case PAN_NO_FIT:
2004 case PAN_FAMILY_TEXT_DISPLAY:
2005 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
2006 /* Which is clearly not what the panose spec says. */
2007 if (TM->tmPitchAndFamily == 0) /* Fixed */
2008 {
2009 TM->tmPitchAndFamily = FF_MODERN;
2010 }
2011 else
2012 {
2013 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
2014 {
2015 case PAN_ANY:
2016 case PAN_NO_FIT:
2017 default:
2018 TM->tmPitchAndFamily |= FF_DONTCARE;
2019 break;
2020
2021 case PAN_SERIF_COVE:
2022 case PAN_SERIF_OBTUSE_COVE:
2023 case PAN_SERIF_SQUARE_COVE:
2024 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2025 case PAN_SERIF_SQUARE:
2026 case PAN_SERIF_THIN:
2027 case PAN_SERIF_BONE:
2028 case PAN_SERIF_EXAGGERATED:
2029 case PAN_SERIF_TRIANGLE:
2030 TM->tmPitchAndFamily |= FF_ROMAN;
2031 break;
2032
2033 case PAN_SERIF_NORMAL_SANS:
2034 case PAN_SERIF_OBTUSE_SANS:
2035 case PAN_SERIF_PERP_SANS:
2036 case PAN_SERIF_FLARED:
2037 case PAN_SERIF_ROUNDED:
2038 TM->tmPitchAndFamily |= FF_SWISS;
2039 break;
2040 }
2041 }
2042 break;
2043 default:
2044 TM->tmPitchAndFamily |= FF_DONTCARE;
2045 }
2046
2047 if (FT_IS_SCALABLE(Face))
2048 {
2049 TM->tmPitchAndFamily |= TMPF_VECTOR;
2050 }
2051 if (FT_IS_SFNT(Face))
2052 {
2053 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
2054 }
2055
2056 TM->tmCharSet = FontGDI->CharSet;
2057 }
2058
2059 static void FASTCALL
2060 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
2061 TT_OS2 *pOS2, TT_HoriHeader *pHori,
2062 FT_WinFNT_HeaderRec *pFNT)
2063 {
2064 FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
2065 }
2066
2067 static NTSTATUS
2068 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
2069 FT_UShort NameID, FT_UShort LangID);
2070
2071 typedef struct FONT_NAMES
2072 {
2073 UNICODE_STRING FamilyNameW; /* family name (TT_NAME_ID_FONT_FAMILY) */
2074 UNICODE_STRING FaceNameW; /* face name (TT_NAME_ID_FULL_NAME) */
2075 UNICODE_STRING StyleNameW; /* style name (TT_NAME_ID_FONT_SUBFAMILY) */
2076 UNICODE_STRING FullNameW; /* unique name (TT_NAME_ID_UNIQUE_ID) */
2077 ULONG OtmSize; /* size of OUTLINETEXTMETRICW with extra data */
2078 } FONT_NAMES, *LPFONT_NAMES;
2079
2080 static __inline void FASTCALL
2081 IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace)
2082 {
2083 ULONG OtmSize;
2084
2085 RtlInitUnicodeString(&Names->FamilyNameW, NULL);
2086 RtlInitUnicodeString(&Names->FaceNameW, NULL);
2087 RtlInitUnicodeString(&Names->StyleNameW, NULL);
2088 RtlInitUnicodeString(&Names->FullNameW, NULL);
2089
2090 /* family name */
2091 IntGetFontLocalizedName(&Names->FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
2092 /* face name */
2093 IntGetFontLocalizedName(&Names->FaceNameW, SharedFace, TT_NAME_ID_FULL_NAME, gusLanguageID);
2094 /* style name */
2095 IntGetFontLocalizedName(&Names->StyleNameW, SharedFace, TT_NAME_ID_FONT_SUBFAMILY, gusLanguageID);
2096 /* unique name (full name) */
2097 IntGetFontLocalizedName(&Names->FullNameW, SharedFace, TT_NAME_ID_UNIQUE_ID, gusLanguageID);
2098
2099 /* Calculate the size of OUTLINETEXTMETRICW with extra data */
2100 OtmSize = sizeof(OUTLINETEXTMETRICW) +
2101 Names->FamilyNameW.Length + sizeof(UNICODE_NULL) +
2102 Names->FaceNameW.Length + sizeof(UNICODE_NULL) +
2103 Names->StyleNameW.Length + sizeof(UNICODE_NULL) +
2104 Names->FullNameW.Length + sizeof(UNICODE_NULL);
2105 Names->OtmSize = OtmSize;
2106 }
2107
2108 static __inline SIZE_T FASTCALL
2109 IntStoreName(const UNICODE_STRING *pName, BYTE *pb)
2110 {
2111 RtlCopyMemory(pb, pName->Buffer, pName->Length);
2112 *(WCHAR *)&pb[pName->Length] = UNICODE_NULL;
2113 return pName->Length + sizeof(UNICODE_NULL);
2114 }
2115
2116 static __inline BYTE *FASTCALL
2117 IntStoreFontNames(const FONT_NAMES *Names, OUTLINETEXTMETRICW *Otm)
2118 {
2119 BYTE *pb = (BYTE *)Otm + sizeof(OUTLINETEXTMETRICW);
2120
2121 /* family name */
2122 Otm->otmpFamilyName = (LPSTR)(pb - (BYTE*) Otm);
2123 pb += IntStoreName(&Names->FamilyNameW, pb);
2124
2125 /* face name */
2126 Otm->otmpFaceName = (LPSTR)(pb - (BYTE*) Otm);
2127 pb += IntStoreName(&Names->FaceNameW, pb);
2128
2129 /* style name */
2130 Otm->otmpStyleName = (LPSTR)(pb - (BYTE*) Otm);
2131 pb += IntStoreName(&Names->StyleNameW, pb);
2132
2133 /* unique name (full name) */
2134 Otm->otmpFullName = (LPSTR)(pb - (BYTE*) Otm);
2135 pb += IntStoreName(&Names->FullNameW, pb);
2136
2137 return pb;
2138 }
2139
2140 static __inline void FASTCALL
2141 IntFreeFontNames(FONT_NAMES *Names)
2142 {
2143 RtlFreeUnicodeString(&Names->FamilyNameW);
2144 RtlFreeUnicodeString(&Names->FaceNameW);
2145 RtlFreeUnicodeString(&Names->StyleNameW);
2146 RtlFreeUnicodeString(&Names->FullNameW);
2147 }
2148
2149 /*************************************************************
2150 * IntGetOutlineTextMetrics
2151 *
2152 */
2153 INT FASTCALL
2154 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
2155 UINT Size,
2156 OUTLINETEXTMETRICW *Otm)
2157 {
2158 TT_OS2 *pOS2;
2159 TT_HoriHeader *pHori;
2160 TT_Postscript *pPost;
2161 FT_Fixed XScale, YScale;
2162 FT_WinFNT_HeaderRec WinFNT;
2163 FT_Error Error;
2164 BYTE *pb;
2165 FONT_NAMES FontNames;
2166 PSHARED_FACE SharedFace = FontGDI->SharedFace;
2167 PSHARED_FACE_CACHE Cache;
2168 FT_Face Face = SharedFace->Face;
2169
2170 if (PRIMARYLANGID(gusLanguageID) == LANG_ENGLISH)
2171 {
2172 Cache = &SharedFace->EnglishUS;
2173 }
2174 else
2175 {
2176 Cache = &SharedFace->UserLanguage;
2177 }
2178
2179 if (Cache->OutlineRequiredSize && Size < Cache->OutlineRequiredSize)
2180 {
2181 return Cache->OutlineRequiredSize;
2182 }
2183
2184 IntInitFontNames(&FontNames, SharedFace);
2185
2186 if (!Cache->OutlineRequiredSize)
2187 {
2188 Cache->OutlineRequiredSize = FontNames.OtmSize;
2189 }
2190
2191 if (Size < Cache->OutlineRequiredSize)
2192 {
2193 IntFreeFontNames(&FontNames);
2194 return Cache->OutlineRequiredSize;
2195 }
2196
2197 XScale = Face->size->metrics.x_scale;
2198 YScale = Face->size->metrics.y_scale;
2199
2200 IntLockFreeType();
2201
2202 pOS2 = FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
2203 if (NULL == pOS2)
2204 {
2205 IntUnLockFreeType();
2206 DPRINT1("Can't find OS/2 table - not TT font?\n");
2207 IntFreeFontNames(&FontNames);
2208 return 0;
2209 }
2210
2211 pHori = FT_Get_Sfnt_Table(Face, FT_SFNT_HHEA);
2212 if (NULL == pHori)
2213 {
2214 IntUnLockFreeType();
2215 DPRINT1("Can't find HHEA table - not TT font?\n");
2216 IntFreeFontNames(&FontNames);
2217 return 0;
2218 }
2219
2220 pPost = FT_Get_Sfnt_Table(Face, FT_SFNT_POST); /* We can live with this failing */
2221
2222 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
2223
2224 Otm->otmSize = Cache->OutlineRequiredSize;
2225
2226 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &WinFNT : 0);
2227
2228 Otm->otmFiller = 0;
2229 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2230 Otm->otmfsSelection = pOS2->fsSelection;
2231 Otm->otmfsType = pOS2->fsType;
2232 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2233 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2234 Otm->otmItalicAngle = 0; /* POST table */
2235 Otm->otmEMSquare = Face->units_per_EM;
2236
2237 #define SCALE_X(value) ((FT_MulFix((value), XScale) + 32) >> 6)
2238 #define SCALE_Y(value) ((FT_MulFix((value), YScale) + 32) >> 6)
2239
2240 Otm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
2241 Otm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
2242 Otm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
2243 Otm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
2244 Otm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
2245 Otm->otmrcFontBox.left = SCALE_X(Face->bbox.xMin);
2246 Otm->otmrcFontBox.right = SCALE_X(Face->bbox.xMax);
2247 Otm->otmrcFontBox.top = SCALE_Y(Face->bbox.yMax);
2248 Otm->otmrcFontBox.bottom = SCALE_Y(Face->bbox.yMin);
2249 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
2250 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
2251 Otm->otmMacLineGap = Otm->otmLineGap;
2252 Otm->otmusMinimumPPEM = 0; /* TT Header */
2253 Otm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
2254 Otm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
2255 Otm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
2256 Otm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
2257 Otm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
2258 Otm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
2259 Otm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
2260 Otm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
2261 Otm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
2262 Otm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
2263
2264 if (!pPost)
2265 {
2266 Otm->otmsUnderscoreSize = 0;
2267 Otm->otmsUnderscorePosition = 0;
2268 }
2269 else
2270 {
2271 Otm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
2272 Otm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
2273 }
2274
2275 #undef SCALE_X
2276 #undef SCALE_Y
2277
2278 IntUnLockFreeType();
2279
2280 pb = IntStoreFontNames(&FontNames, Otm);
2281 ASSERT(pb - (BYTE*)Otm == Cache->OutlineRequiredSize);
2282
2283 IntFreeFontNames(&FontNames);
2284
2285 return Cache->OutlineRequiredSize;
2286 }
2287
2288 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
2289 static BYTE
2290 CharSetFromLangID(LANGID LangID)
2291 {
2292 /* FIXME: Add more and fix if wrong */
2293 switch (PRIMARYLANGID(LangID))
2294 {
2295 case LANG_CHINESE:
2296 switch (SUBLANGID(LangID))
2297 {
2298 case SUBLANG_CHINESE_TRADITIONAL:
2299 return CHINESEBIG5_CHARSET;
2300 case SUBLANG_CHINESE_SIMPLIFIED:
2301 default:
2302 break;
2303 }
2304 return GB2312_CHARSET;
2305
2306 case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
2307 case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
2308 return EASTEUROPE_CHARSET;
2309
2310 case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
2311 case LANG_SERBIAN: case LANG_UKRAINIAN:
2312 return RUSSIAN_CHARSET;
2313
2314 case LANG_ARABIC: return ARABIC_CHARSET;
2315 case LANG_GREEK: return GREEK_CHARSET;
2316 case LANG_HEBREW: return HEBREW_CHARSET;
2317 case LANG_JAPANESE: return SHIFTJIS_CHARSET;
2318 case LANG_KOREAN: return JOHAB_CHARSET;
2319 case LANG_TURKISH: return TURKISH_CHARSET;
2320 case LANG_THAI: return THAI_CHARSET;
2321 case LANG_LATVIAN: return BALTIC_CHARSET;
2322 case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
2323
2324 case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
2325 case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
2326 case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
2327 case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
2328 case LANG_SWEDISH: default:
2329 return ANSI_CHARSET;
2330 }
2331 }
2332
2333 static void
2334 SwapEndian(LPVOID pvData, DWORD Size)
2335 {
2336 BYTE b, *pb = pvData;
2337 Size /= 2;
2338 while (Size-- > 0)
2339 {
2340 b = pb[0];
2341 pb[0] = pb[1];
2342 pb[1] = b;
2343 ++pb; ++pb;
2344 }
2345 }
2346
2347 static NTSTATUS
2348 DuplicateUnicodeString(PUNICODE_STRING Source, PUNICODE_STRING Destination)
2349 {
2350 NTSTATUS Status = STATUS_NO_MEMORY;
2351 UNICODE_STRING Tmp;
2352
2353 Tmp.Buffer = ExAllocatePoolWithTag(PagedPool, Source->MaximumLength, TAG_USTR);
2354 if (Tmp.Buffer)
2355 {
2356 Tmp.MaximumLength = Source->MaximumLength;
2357 Tmp.Length = 0;
2358 RtlCopyUnicodeString(&Tmp, Source);
2359
2360 Destination->MaximumLength = Tmp.MaximumLength;
2361 Destination->Length = Tmp.Length;
2362 Destination->Buffer = Tmp.Buffer;
2363
2364 Status = STATUS_SUCCESS;
2365 }
2366
2367 return Status;
2368 }
2369
2370 static NTSTATUS
2371 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
2372 FT_UShort NameID, FT_UShort LangID)
2373 {
2374 FT_SfntName Name;
2375 INT i, Count, BestIndex, Score, BestScore;
2376 FT_Error Error;
2377 NTSTATUS Status = STATUS_NOT_FOUND;
2378 ANSI_STRING AnsiName;
2379 PSHARED_FACE_CACHE Cache;
2380 FT_Face Face = SharedFace->Face;
2381
2382 RtlFreeUnicodeString(pNameW);
2383
2384 /* select cache */
2385 if (PRIMARYLANGID(LangID) == LANG_ENGLISH)
2386 {
2387 Cache = &SharedFace->EnglishUS;
2388 }
2389 else
2390 {
2391 Cache = &SharedFace->UserLanguage;
2392 }
2393
2394 /* use cache if available */
2395 if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer)
2396 {
2397 return DuplicateUnicodeString(&Cache->FontFamily, pNameW);
2398 }
2399 if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer)
2400 {
2401 return DuplicateUnicodeString(&Cache->FullName, pNameW);
2402 }
2403
2404 BestIndex = -1;
2405 BestScore = 0;
2406
2407 Count = FT_Get_Sfnt_Name_Count(Face);
2408 for (i = 0; i < Count; ++i)
2409 {
2410 Error = FT_Get_Sfnt_Name(Face, i, &Name);
2411 if (Error)
2412 {
2413 continue; /* failure */
2414 }
2415
2416 if (Name.name_id != NameID)
2417 {
2418 continue; /* mismatched */
2419 }
2420
2421 if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
2422 (Name.encoding_id != TT_MS_ID_UNICODE_CS &&
2423 Name.encoding_id != TT_MS_ID_SYMBOL_CS))
2424 {
2425 continue; /* not Microsoft Unicode name */
2426 }
2427
2428 if (Name.string == NULL || Name.string_len == 0 ||
2429 (Name.string[0] == 0 && Name.string[1] == 0))
2430 {
2431 continue; /* invalid string */
2432 }
2433
2434 if (Name.language_id == LangID)
2435 {
2436 Score = 30;
2437 BestIndex = i;
2438 break; /* best match */
2439 }
2440 else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID))
2441 {
2442 Score = 20;
2443 }
2444 else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH)
2445 {
2446 Score = 10;
2447 }
2448 else
2449 {
2450 Score = 0;
2451 }
2452
2453 if (Score > BestScore)
2454 {
2455 BestScore = Score;
2456 BestIndex = i;
2457 }
2458 }
2459
2460 if (BestIndex >= 0)
2461 {
2462 /* store the best name */
2463 Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
2464 if (!Error)
2465 {
2466 /* NOTE: Name.string is not null-terminated */
2467 UNICODE_STRING Tmp;
2468 Tmp.Buffer = (PWCH)Name.string;
2469 Tmp.Length = Tmp.MaximumLength = Name.string_len;
2470
2471 pNameW->Length = 0;
2472 pNameW->MaximumLength = Name.string_len + sizeof(WCHAR);
2473 pNameW->Buffer = ExAllocatePoolWithTag(PagedPool, pNameW->MaximumLength, TAG_USTR);
2474
2475 if (pNameW->Buffer)
2476 {
2477 Status = RtlAppendUnicodeStringToString(pNameW, &Tmp);
2478 if (Status == STATUS_SUCCESS)
2479 {
2480 /* Convert UTF-16 big endian to little endian */
2481 SwapEndian(pNameW->Buffer, pNameW->Length);
2482 }
2483 }
2484 else
2485 {
2486 Status = STATUS_INSUFFICIENT_RESOURCES;
2487 }
2488 }
2489 }
2490
2491 if (!NT_SUCCESS(Status))
2492 {
2493 /* defaulted */
2494 if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
2495 {
2496 RtlInitAnsiString(&AnsiName, Face->style_name);
2497 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2498 }
2499 else
2500 {
2501 RtlInitAnsiString(&AnsiName, Face->family_name);
2502 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2503 }
2504 }
2505
2506 if (NT_SUCCESS(Status))
2507 {
2508 /* make cache */
2509 if (NameID == TT_NAME_ID_FONT_FAMILY)
2510 {
2511 ASSERT_FREETYPE_LOCK_NOT_HELD();
2512 IntLockFreeType();
2513 if (!Cache->FontFamily.Buffer)
2514 DuplicateUnicodeString(pNameW, &Cache->FontFamily);
2515 IntUnLockFreeType();
2516 }
2517 else if (NameID == TT_NAME_ID_FULL_NAME)
2518 {
2519 ASSERT_FREETYPE_LOCK_NOT_HELD();
2520 IntLockFreeType();
2521 if (!Cache->FullName.Buffer)
2522 DuplicateUnicodeString(pNameW, &Cache->FullName);
2523 IntUnLockFreeType();
2524 }
2525 }
2526
2527 return Status;
2528 }
2529
2530 static void FASTCALL
2531 FontFamilyFillInfo(PFONTFAMILYINFO Info, LPCWSTR FaceName,
2532 LPCWSTR FullName, PFONTGDI FontGDI)
2533 {
2534 ANSI_STRING StyleA;
2535 UNICODE_STRING StyleW;
2536 TT_OS2 *pOS2;
2537 FONTSIGNATURE fs;
2538 CHARSETINFO CharSetInfo;
2539 unsigned i, Size;
2540 OUTLINETEXTMETRICW *Otm;
2541 LOGFONTW *Lf;
2542 TEXTMETRICW *TM;
2543 NEWTEXTMETRICW *Ntm;
2544 DWORD fs0;
2545 NTSTATUS status;
2546 PSHARED_FACE SharedFace = FontGDI->SharedFace;
2547 FT_Face Face = SharedFace->Face;
2548 UNICODE_STRING NameW;
2549
2550 RtlInitUnicodeString(&NameW, NULL);
2551 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
2552 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2553 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2554 if (!Otm)
2555 {
2556 return;
2557 }
2558 Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2559 if (!Size)
2560 {
2561 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2562 return;
2563 }
2564
2565 Lf = &Info->EnumLogFontEx.elfLogFont;
2566 TM = &Otm->otmTextMetrics;
2567
2568 Lf->lfHeight = TM->tmHeight;
2569 Lf->lfWidth = TM->tmAveCharWidth;
2570 Lf->lfWeight = TM->tmWeight;
2571 Lf->lfItalic = TM->tmItalic;
2572 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
2573 Lf->lfCharSet = TM->tmCharSet;
2574 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
2575 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
2576 Lf->lfQuality = PROOF_QUALITY;
2577
2578 Ntm = &Info->NewTextMetricEx.ntmTm;
2579 Ntm->tmHeight = TM->tmHeight;
2580 Ntm->tmAscent = TM->tmAscent;
2581 Ntm->tmDescent = TM->tmDescent;
2582 Ntm->tmInternalLeading = TM->tmInternalLeading;
2583 Ntm->tmExternalLeading = TM->tmExternalLeading;
2584 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
2585 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
2586 Ntm->tmWeight = TM->tmWeight;
2587 Ntm->tmOverhang = TM->tmOverhang;
2588 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
2589 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
2590 Ntm->tmFirstChar = TM->tmFirstChar;
2591 Ntm->tmLastChar = TM->tmLastChar;
2592 Ntm->tmDefaultChar = TM->tmDefaultChar;
2593 Ntm->tmBreakChar = TM->tmBreakChar;
2594 Ntm->tmItalic = TM->tmItalic;
2595 Ntm->tmUnderlined = TM->tmUnderlined;
2596 Ntm->tmStruckOut = TM->tmStruckOut;
2597 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
2598 Ntm->tmCharSet = TM->tmCharSet;
2599 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
2600
2601 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
2602
2603 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
2604
2605 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
2606 ? TRUETYPE_FONTTYPE : 0);
2607
2608 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
2609 Info->FontType |= RASTER_FONTTYPE;
2610
2611
2612 /* face name */
2613 if (!FaceName)
2614 FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
2615
2616 RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
2617
2618 /* full name */
2619 if (!FullName)
2620 FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName);
2621
2622 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2623 sizeof(Info->EnumLogFontEx.elfFullName),
2624 FullName);
2625
2626 RtlInitAnsiString(&StyleA, Face->style_name);
2627 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
2628 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
2629 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
2630 if (!NT_SUCCESS(status))
2631 {
2632 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2633 return;
2634 }
2635 Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
2636
2637 IntLockFreeType();
2638 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2639
2640 if (!pOS2)
2641 {
2642 IntUnLockFreeType();
2643 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2644 return;
2645 }
2646
2647 Ntm->ntmSizeEM = Otm->otmEMSquare;
2648 Ntm->ntmCellHeight = (FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent;
2649 Ntm->ntmAvgWidth = 0;
2650
2651 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2652
2653 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2654 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2655 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2656 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2657 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2658 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2659
2660 if (0 == pOS2->version)
2661 {
2662 FT_UInt Dummy;
2663
2664 if (FT_Get_First_Char(Face, &Dummy) < 0x100)
2665 fs.fsCsb[0] |= FS_LATIN1;
2666 else
2667 fs.fsCsb[0] |= FS_SYMBOL;
2668 }
2669 IntUnLockFreeType();
2670
2671 if (fs.fsCsb[0] == 0)
2672 {
2673 /* Let's see if we can find any interesting cmaps */
2674 for (i = 0; i < (UINT)Face->num_charmaps; i++)
2675 {
2676 switch (Face->charmaps[i]->encoding)
2677 {
2678 case FT_ENCODING_UNICODE:
2679 case FT_ENCODING_APPLE_ROMAN:
2680 fs.fsCsb[0] |= FS_LATIN1;
2681 break;
2682 case FT_ENCODING_MS_SYMBOL:
2683 fs.fsCsb[0] |= FS_SYMBOL;
2684 break;
2685 default:
2686 break;
2687 }
2688 }
2689 }
2690
2691 for (i = 0; i < MAXTCIINDEX; i++)
2692 {
2693 fs0 = 1L << i;
2694 if (fs.fsCsb[0] & fs0)
2695 {
2696 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
2697 {
2698 CharSetInfo.ciCharset = DEFAULT_CHARSET;
2699 }
2700 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
2701 {
2702 if (g_ElfScripts[i])
2703 wcscpy(Info->EnumLogFontEx.elfScript, g_ElfScripts[i]);
2704 else
2705 {
2706 DPRINT1("Unknown elfscript for bit %u\n", i);
2707 }
2708 }
2709 }
2710 }
2711 Info->NewTextMetricEx.ntmFontSig = fs;
2712 }
2713
2714 static BOOLEAN FASTCALL
2715 GetFontFamilyInfoForList(const LOGFONTW *LogFont,
2716 PFONTFAMILYINFO Info,
2717 LPCWSTR NominalName,
2718 LONG *pCount,
2719 LONG MaxCount,
2720 PLIST_ENTRY Head)
2721 {
2722 PLIST_ENTRY Entry;
2723 PFONT_ENTRY CurrentEntry;
2724 FONTGDI *FontGDI;
2725 FONTFAMILYINFO InfoEntry;
2726 LONG Count = *pCount;
2727
2728 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
2729 {
2730 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2731 FontGDI = CurrentEntry->Font;
2732 ASSERT(FontGDI);
2733
2734 if (LogFont->lfCharSet != DEFAULT_CHARSET &&
2735 LogFont->lfCharSet != FontGDI->CharSet)
2736 {
2737 continue; /* charset mismatch */
2738 }
2739
2740 /* get one info entry */
2741 FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
2742
2743 if (LogFont->lfFaceName[0] != UNICODE_NULL)
2744 {
2745 /* check name */
2746 if (_wcsnicmp(LogFont->lfFaceName,
2747 InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
2748 RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0 &&
2749 _wcsnicmp(LogFont->lfFaceName,
2750 InfoEntry.EnumLogFontEx.elfFullName,
2751 RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0)
2752 {
2753 continue;
2754 }
2755 }
2756
2757 if (NominalName)
2758 {
2759 /* store the nominal name */
2760 RtlStringCbCopyW(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
2761 sizeof(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName),
2762 NominalName);
2763 }
2764
2765 /* store one entry to Info */
2766 if (0 <= Count && Count < MaxCount)
2767 {
2768 RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
2769 }
2770 Count++;
2771 }
2772
2773 *pCount = Count;
2774
2775 return TRUE;
2776 }
2777
2778 static BOOLEAN FASTCALL
2779 GetFontFamilyInfoForSubstitutes(const LOGFONTW *LogFont,
2780 PFONTFAMILYINFO Info,
2781 LONG *pCount,
2782 LONG MaxCount)
2783 {
2784 PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead;
2785 PFONTSUBST_ENTRY pCurrentEntry;
2786 PUNICODE_STRING pFromW, pToW;
2787 LOGFONTW lf = *LogFont;
2788 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
2789
2790 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
2791 {
2792 pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
2793
2794 pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
2795 if (LogFont->lfFaceName[0] != UNICODE_NULL)
2796 {
2797 /* check name */
2798 if (_wcsicmp(LogFont->lfFaceName, pFromW->Buffer) != 0)
2799 continue; /* mismatch */
2800 }
2801
2802 pToW = &pCurrentEntry->FontNames[FONTSUBST_TO];
2803 if (RtlEqualUnicodeString(pFromW, pToW, TRUE) &&
2804 pCurrentEntry->CharSets[FONTSUBST_FROM] ==
2805 pCurrentEntry->CharSets[FONTSUBST_TO])
2806 {
2807 /* identical mapping */
2808 continue;
2809 }
2810
2811 /* substitute and get the real name */
2812 IntUnicodeStringToBuffer(lf.lfFaceName, sizeof(lf.lfFaceName), pFromW);
2813 SubstituteFontRecurse(&lf);
2814 if (LogFont->lfCharSet != DEFAULT_CHARSET && LogFont->lfCharSet != lf.lfCharSet)
2815 continue;
2816
2817 /* search in global fonts */
2818 IntLockGlobalFonts();
2819 GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount, &g_FontListHead);
2820 IntUnLockGlobalFonts();
2821
2822 /* search in private fonts */
2823 IntLockProcessPrivateFonts(Win32Process);
2824 GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount,
2825 &Win32Process->PrivateFontListHead);
2826 IntUnLockProcessPrivateFonts(Win32Process);
2827
2828 if (LogFont->lfFaceName[0] != UNICODE_NULL)
2829 {
2830 /* it's already matched to the exact name and charset if the name
2831 was specified at here, then so don't scan more for another name */
2832 break;
2833 }
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 unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3017 {
3018 TTPOLYGONHEADER *pph;
3019 TTPOLYCURVE *ppc;
3020 int needed = 0, point = 0, contour, first_pt;
3021 unsigned int pph_start, cpfx;
3022 DWORD type;
3023
3024 for (contour = 0; contour < outline->n_contours; contour++)
3025 {
3026 /* Ignore contours containing one point */
3027 if (point == outline->contours[contour])
3028 {
3029 point++;
3030 continue;
3031 }
3032
3033 pph_start = needed;
3034 pph = (TTPOLYGONHEADER *)(buf + needed);
3035 first_pt = point;
3036 if (buf)
3037 {
3038 pph->dwType = TT_POLYGON_TYPE;
3039 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3040 }
3041 needed += sizeof(*pph);
3042 point++;
3043 while (point <= outline->contours[contour])
3044 {
3045 ppc = (TTPOLYCURVE *)(buf + needed);
3046 type = outline->tags[point] & FT_Curve_Tag_On ?
3047 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3048 cpfx = 0;
3049 do
3050 {
3051 if (buf)
3052 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3053 cpfx++;
3054 point++;
3055 } while (point <= outline->contours[contour] &&
3056 (outline->tags[point] & FT_Curve_Tag_On) ==
3057 (outline->tags[point-1] & FT_Curve_Tag_On));
3058 /* At the end of a contour Windows adds the start point, but
3059 only for Beziers */
3060 if (point > outline->contours[contour] &&
3061 !(outline->tags[point-1] & FT_Curve_Tag_On))
3062 {
3063 if (buf)
3064 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3065 cpfx++;
3066 }
3067 else if (point <= outline->contours[contour] &&
3068 outline->tags[point] & FT_Curve_Tag_On)
3069 {
3070 /* add closing pt for bezier */
3071 if (buf)
3072 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3073 cpfx++;
3074 point++;
3075 }
3076 if (buf)
3077 {
3078 ppc->wType = type;
3079 ppc->cpfx = cpfx;
3080 }
3081 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3082 }
3083 if (buf)
3084 pph->cb = needed - pph_start;
3085 }
3086 return needed;
3087 }
3088
3089 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3090 {
3091 /* Convert the quadratic Beziers to cubic Beziers.
3092 The parametric eqn for a cubic Bezier is, from PLRM:
3093 r(t) = at^3 + bt^2 + ct + r0
3094 with the control points:
3095 r1 = r0 + c/3
3096 r2 = r1 + (c + b)/3
3097 r3 = r0 + c + b + a
3098
3099 A quadratic Bezier has the form:
3100 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3101
3102 So equating powers of t leads to:
3103 r1 = 2/3 p1 + 1/3 p0
3104 r2 = 2/3 p1 + 1/3 p2
3105 and of course r0 = p0, r3 = p2
3106 */
3107 int contour, point = 0, first_pt;
3108 TTPOLYGONHEADER *pph;
3109 TTPOLYCURVE *ppc;
3110 DWORD pph_start, cpfx, type;
3111 FT_Vector cubic_control[4];
3112 unsigned int needed = 0;
3113
3114 for (contour = 0; contour < outline->n_contours; contour++)
3115 {
3116 pph_start = needed;
3117 pph = (TTPOLYGONHEADER *)(buf + needed);
3118 first_pt = point;
3119 if (buf)
3120 {
3121 pph->dwType = TT_POLYGON_TYPE;
3122 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3123 }
3124 needed += sizeof(*pph);
3125 point++;
3126 while (point <= outline->contours[contour])
3127 {
3128 ppc = (TTPOLYCURVE *)(buf + needed);
3129 type = outline->tags[point] & FT_Curve_Tag_On ?
3130 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3131 cpfx = 0;
3132 do
3133 {
3134 if (type == TT_PRIM_LINE)
3135 {
3136 if (buf)
3137 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3138 cpfx++;
3139 point++;
3140 }
3141 else
3142 {
3143 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3144 so cpfx = 3n */
3145
3146 /* FIXME: Possible optimization in endpoint calculation
3147 if there are two consecutive curves */
3148 cubic_control[0] = outline->points[point-1];
3149 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3150 {
3151 cubic_control[0].x += outline->points[point].x + 1;
3152 cubic_control[0].y += outline->points[point].y + 1;
3153 cubic_control[0].x >>= 1;
3154 cubic_control[0].y >>= 1;
3155 }
3156 if (point+1 > outline->contours[contour])
3157 cubic_control[3] = outline->points[first_pt];
3158 else
3159 {
3160 cubic_control[3] = outline->points[point+1];
3161 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3162 {
3163 cubic_control[3].x += outline->points[point].x + 1;
3164 cubic_control[3].y += outline->points[point].y + 1;
3165 cubic_control[3].x >>= 1;
3166 cubic_control[3].y >>= 1;
3167 }
3168 }
3169 /* r1 = 1/3 p0 + 2/3 p1
3170 r2 = 1/3 p2 + 2/3 p1 */
3171 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3172 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3173 cubic_control[2] = cubic_control[1];
3174 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3175 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3176 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3177 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3178 if (buf)
3179 {
3180 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3181 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3182 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3183 }
3184 cpfx += 3;
3185 point++;
3186 }
3187 } while (point <= outline->contours[contour] &&
3188 (outline->tags[point] & FT_Curve_Tag_On) ==
3189 (outline->tags[point-1] & FT_Curve_Tag_On));
3190 /* At the end of a contour Windows adds the start point,
3191 but only for Beziers and we've already done that.
3192 */
3193 if (point <= outline->contours[contour] &&
3194 outline->tags[point] & FT_Curve_Tag_On)
3195 {
3196 /* This is the closing pt of a bezier, but we've already
3197 added it, so just inc point and carry on */
3198 point++;
3199 }
3200 if (buf)
3201 {
3202 ppc->wType = type;
3203 ppc->cpfx = cpfx;
3204 }
3205 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3206 }
3207 if (buf)
3208 pph->cb = needed - pph_start;
3209 }
3210 return needed;
3211 }
3212
3213 static FT_Error
3214 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
3215 {
3216 FT_Error error;
3217 FT_Size_RequestRec req;
3218 FT_Face face = FontGDI->SharedFace->Face;
3219 TT_OS2 *pOS2;
3220 TT_HoriHeader *pHori;
3221 FT_WinFNT_HeaderRec WinFNT;
3222 LONG Ascent, Descent, Sum, EmHeight64;
3223
3224 lfWidth = abs(lfWidth);
3225 if (lfHeight == 0)
3226 {
3227 if (lfWidth == 0)
3228 {
3229 DPRINT("lfHeight and lfWidth are zero.\n");
3230 lfHeight = -16;
3231 }
3232 else
3233 {
3234 lfHeight = lfWidth;
3235 }
3236 }
3237
3238 if (lfHeight == -1)
3239 lfHeight = -2;
3240
3241 ASSERT_FREETYPE_LOCK_HELD();
3242 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
3243 pHori = (TT_HoriHeader *)FT_Get_Sfnt_Table(face, FT_SFNT_HHEA);