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