3b653270714a7449a3b1c4b0fa6e382482911122
[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 FORCEINLINE VOID FASTCALL
744 FtSetCoordinateTransform(
745 FT_Face face,
746 PMATRIX pmx)
747 {
748 FT_Matrix mat;
749 FtMatrixFromMx(&mat, pmx);
750
751 /* Set the transformation matrix */
752 FT_Set_Transform(face, &mat, 0);
753 }
754
755 static BOOL
756 SubstituteFontByList(PLIST_ENTRY pHead,
757 PUNICODE_STRING pOutputName,
758 PUNICODE_STRING pInputName,
759 BYTE RequestedCharSet,
760 BYTE CharSetMap[FONTSUBST_FROM_AND_TO])
761 {
762 PLIST_ENTRY pListEntry;
763 PFONTSUBST_ENTRY pSubstEntry;
764 BYTE CharSets[FONTSUBST_FROM_AND_TO];
765
766 CharSetMap[FONTSUBST_FROM] = DEFAULT_CHARSET;
767 CharSetMap[FONTSUBST_TO] = RequestedCharSet;
768
769 /* for each list entry */
770 for (pListEntry = pHead->Flink;
771 pListEntry != pHead;
772 pListEntry = pListEntry->Flink)
773 {
774 pSubstEntry =
775 (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_ENTRY, ListEntry);
776
777 CharSets[FONTSUBST_FROM] = pSubstEntry->CharSets[FONTSUBST_FROM];
778
779 if (CharSets[FONTSUBST_FROM] != DEFAULT_CHARSET &&
780 CharSets[FONTSUBST_FROM] != RequestedCharSet)
781 {
782 continue; /* not matched */
783 }
784
785 /* does charset number exist? (to) */
786 if (pSubstEntry->CharSets[FONTSUBST_TO] != DEFAULT_CHARSET)
787 {
788 CharSets[FONTSUBST_TO] = pSubstEntry->CharSets[FONTSUBST_TO];
789 }
790 else
791 {
792 CharSets[FONTSUBST_TO] = RequestedCharSet;
793 }
794
795 /* does font name match? */
796 if (!RtlEqualUnicodeString(&pSubstEntry->FontNames[FONTSUBST_FROM],
797 pInputName, TRUE))
798 {
799 continue; /* not matched */
800 }
801
802 /* update *pOutputName */
803 *pOutputName = pSubstEntry->FontNames[FONTSUBST_TO];
804
805 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
806 {
807 /* update CharSetMap */
808 CharSetMap[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
809 CharSetMap[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
810 }
811 return TRUE; /* success */
812 }
813
814 return FALSE;
815 }
816
817 static VOID
818 IntUnicodeStringToBuffer(LPWSTR pszBuffer, USHORT cbBuffer, const UNICODE_STRING *pString)
819 {
820 USHORT cbLength = pString->Length;
821
822 if (cbBuffer < sizeof(UNICODE_NULL))
823 return;
824
825 if (cbLength > cbBuffer - sizeof(UNICODE_NULL))
826 cbLength = cbBuffer - sizeof(UNICODE_NULL);
827
828 RtlCopyMemory(pszBuffer, pString->Buffer, cbLength);
829 pszBuffer[cbLength / sizeof(WCHAR)] = UNICODE_NULL;
830 }
831
832 static BOOL
833 SubstituteFontRecurse(LOGFONTW* pLogFont)
834 {
835 UINT RecurseCount = 5;
836 UNICODE_STRING OutputNameW = { 0 };
837 BYTE CharSetMap[FONTSUBST_FROM_AND_TO];
838 BOOL Found;
839 UNICODE_STRING InputNameW;
840
841 if (pLogFont->lfFaceName[0] == UNICODE_NULL)
842 return FALSE;
843
844 RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
845
846 while (RecurseCount-- > 0)
847 {
848 Found = SubstituteFontByList(&g_FontSubstListHead,
849 &OutputNameW, &InputNameW,
850 pLogFont->lfCharSet, CharSetMap);
851 if (!Found)
852 break;
853
854 IntUnicodeStringToBuffer(pLogFont->lfFaceName, sizeof(pLogFont->lfFaceName), &OutputNameW);
855
856 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
857 CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
858 {
859 pLogFont->lfCharSet = CharSetMap[FONTSUBST_TO];
860 }
861 }
862
863 return TRUE; /* success */
864 }
865
866 /*
867 * IntLoadSystemFonts
868 *
869 * Search the system font directory and adds each font found.
870 */
871 VOID FASTCALL
872 IntLoadSystemFonts(VOID)
873 {
874 OBJECT_ATTRIBUTES ObjectAttributes;
875 UNICODE_STRING Directory, FileName, TempString;
876 IO_STATUS_BLOCK Iosb;
877 HANDLE hDirectory;
878 BYTE *DirInfoBuffer;
879 PFILE_DIRECTORY_INFORMATION DirInfo;
880 BOOLEAN bRestartScan = TRUE;
881 NTSTATUS Status;
882 INT i;
883 static UNICODE_STRING SearchPatterns[] =
884 {
885 RTL_CONSTANT_STRING(L"*.ttf"),
886 RTL_CONSTANT_STRING(L"*.ttc"),
887 RTL_CONSTANT_STRING(L"*.otf"),
888 RTL_CONSTANT_STRING(L"*.otc"),
889 RTL_CONSTANT_STRING(L"*.fon"),
890 RTL_CONSTANT_STRING(L"*.fnt")
891 };
892
893 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
894
895 InitializeObjectAttributes(
896 &ObjectAttributes,
897 &Directory,
898 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
899 NULL,
900 NULL);
901
902 Status = ZwOpenFile(
903 &hDirectory,
904 SYNCHRONIZE | FILE_LIST_DIRECTORY,
905 &ObjectAttributes,
906 &Iosb,
907 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
908 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
909
910 if (NT_SUCCESS(Status))
911 {
912 for (i = 0; i < _countof(SearchPatterns); ++i)
913 {
914 DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
915 if (DirInfoBuffer == NULL)
916 {
917 ZwClose(hDirectory);
918 return;
919 }
920
921 FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
922 if (FileName.Buffer == NULL)
923 {
924 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
925 ZwClose(hDirectory);
926 return;
927 }
928 FileName.Length = 0;
929 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
930
931 while (1)
932 {
933 Status = ZwQueryDirectoryFile(
934 hDirectory,
935 NULL,
936 NULL,
937 NULL,
938 &Iosb,
939 DirInfoBuffer,
940 0x4000,
941 FileDirectoryInformation,
942 FALSE,
943 &SearchPatterns[i],
944 bRestartScan);
945
946 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
947 {
948 break;
949 }
950
951 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
952 while (1)
953 {
954 TempString.Buffer = DirInfo->FileName;
955 TempString.Length =
956 TempString.MaximumLength = DirInfo->FileNameLength;
957 RtlCopyUnicodeString(&FileName, &Directory);
958 RtlAppendUnicodeStringToString(&FileName, &TempString);
959 IntGdiAddFontResource(&FileName, 0);
960 if (DirInfo->NextEntryOffset == 0)
961 break;
962 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
963 }
964
965 bRestartScan = FALSE;
966 }
967
968 ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
969 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
970 }
971 ZwClose(hDirectory);
972 }
973 }
974
975 static BYTE
976 ItalicFromStyle(const char *style_name)
977 {
978 if (style_name == NULL || style_name[0] == 0)
979 return FALSE;
980 if (strstr(style_name, "Italic") != NULL)
981 return TRUE;
982 if (strstr(style_name, "Oblique") != NULL)
983 return TRUE;
984 return FALSE;
985 }
986
987 static LONG
988 WeightFromStyle(const char *style_name)
989 {
990 if (style_name == NULL || style_name[0] == 0)
991 return FW_NORMAL;
992 if (strstr(style_name, "Regular") != NULL)
993 return FW_REGULAR;
994 if (strstr(style_name, "Normal") != NULL)
995 return FW_NORMAL;
996 if (strstr(style_name, "SemiBold") != NULL)
997 return FW_SEMIBOLD;
998 if (strstr(style_name, "UltraBold") != NULL)
999 return FW_ULTRABOLD;
1000 if (strstr(style_name, "DemiBold") != NULL)
1001 return FW_DEMIBOLD;
1002 if (strstr(style_name, "ExtraBold") != NULL)
1003 return FW_EXTRABOLD;
1004 if (strstr(style_name, "Bold") != NULL)
1005 return FW_BOLD;
1006 if (strstr(style_name, "UltraLight") != NULL)
1007 return FW_ULTRALIGHT;
1008 if (strstr(style_name, "ExtraLight") != NULL)
1009 return FW_EXTRALIGHT;
1010 if (strstr(style_name, "Light") != NULL)
1011 return FW_LIGHT;
1012 if (strstr(style_name, "Hairline") != NULL)
1013 return 50;
1014 if (strstr(style_name, "Book") != NULL)
1015 return 350;
1016 if (strstr(style_name, "ExtraBlack") != NULL)
1017 return 950;
1018 if (strstr(style_name, "UltraBlack") != NULL)
1019 return 1000;
1020 if (strstr(style_name, "Black") != NULL)
1021 return FW_BLACK;
1022 if (strstr(style_name, "Medium") != NULL)
1023 return FW_MEDIUM;
1024 if (strstr(style_name, "Thin") != NULL)
1025 return FW_THIN;
1026 if (strstr(style_name, "Heavy") != NULL)
1027 return FW_HEAVY;
1028 return FW_NORMAL;
1029 }
1030
1031 static FT_Error
1032 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight);
1033
1034 static INT FASTCALL
1035 IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
1036 PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
1037 {
1038 FT_Error Error;
1039 PFONT_ENTRY Entry;
1040 FONT_ENTRY_MEM* PrivateEntry = NULL;
1041 FONTGDI * FontGDI;
1042 NTSTATUS Status;
1043 FT_Face Face;
1044 ANSI_STRING AnsiString;
1045 FT_WinFNT_HeaderRec WinFNT;
1046 INT FaceCount = 0, CharSetCount = 0;
1047 PUNICODE_STRING pFileName = pLoadFont->pFileName;
1048 DWORD Characteristics = pLoadFont->Characteristics;
1049 PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
1050 TT_OS2 * pOS2;
1051 INT BitIndex;
1052 FT_UShort os2_version;
1053 FT_ULong os2_ulCodePageRange1;
1054 FT_UShort os2_usWeightClass;
1055
1056 if (SharedFace == NULL && CharSetIndex == -1)
1057 {
1058 /* load a face from memory */
1059 IntLockFreeType();
1060 Error = FT_New_Memory_Face(
1061 g_FreeTypeLibrary,
1062 pLoadFont->Memory->Buffer,
1063 pLoadFont->Memory->BufferSize,
1064 ((FontIndex != -1) ? FontIndex : 0),
1065 &Face);
1066
1067 if (!Error)
1068 SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
1069
1070 IntUnLockFreeType();
1071
1072 if (!Error && FT_IS_SFNT(Face))
1073 pLoadFont->IsTrueType = TRUE;
1074
1075 if (Error || SharedFace == NULL)
1076 {
1077 if (SharedFace)
1078 SharedFace_Release(SharedFace);
1079
1080 if (Error == FT_Err_Unknown_File_Format)
1081 DPRINT1("Unknown font file format\n");
1082 else
1083 DPRINT1("Error reading font (error code: %d)\n", Error);
1084 return 0; /* failure */
1085 }
1086 }
1087 else
1088 {
1089 Face = SharedFace->Face;
1090 IntLockFreeType();
1091 SharedFace_AddRef(SharedFace);
1092 IntUnLockFreeType();
1093 }
1094
1095 /* allocate a FONT_ENTRY */
1096 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
1097 if (!Entry)
1098 {
1099 SharedFace_Release(SharedFace);
1100 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1101 return 0; /* failure */
1102 }
1103
1104 /* allocate a FONTGDI */
1105 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
1106 if (!FontGDI)
1107 {
1108 SharedFace_Release(SharedFace);
1109 ExFreePoolWithTag(Entry, TAG_FONT);
1110 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1111 return 0; /* failure */
1112 }
1113
1114 /* set file name */
1115 if (pFileName)
1116 {
1117 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool,
1118 pFileName->Length + sizeof(UNICODE_NULL),
1119 GDITAG_PFF);
1120 if (FontGDI->Filename == NULL)
1121 {
1122 EngFreeMem(FontGDI);
1123 SharedFace_Release(SharedFace);
1124 ExFreePoolWithTag(Entry, TAG_FONT);
1125 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1126 return 0; /* failure */
1127 }
1128
1129 RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
1130 FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1131 }
1132 else
1133 {
1134 FontGDI->Filename = NULL;
1135
1136 PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT);
1137 if (!PrivateEntry)
1138 {
1139 if (FontGDI->Filename)
1140 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1141 EngFreeMem(FontGDI);
1142 SharedFace_Release(SharedFace);
1143 ExFreePoolWithTag(Entry, TAG_FONT);
1144 return 0;
1145 }
1146
1147 PrivateEntry->Entry = Entry;
1148 if (pLoadFont->PrivateEntry)
1149 {
1150 InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry);
1151 }
1152 else
1153 {
1154 InitializeListHead(&PrivateEntry->ListEntry);
1155 pLoadFont->PrivateEntry = PrivateEntry;
1156 }
1157 }
1158
1159 /* set face */
1160 FontGDI->SharedFace = SharedFace;
1161 FontGDI->CharSet = ANSI_CHARSET;
1162 FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name);
1163 FontGDI->RequestItalic = FALSE;
1164 FontGDI->OriginalWeight = WeightFromStyle(Face->style_name);
1165 FontGDI->RequestWeight = FW_NORMAL;
1166
1167 RtlInitAnsiString(&AnsiString, Face->family_name);
1168 Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiString, TRUE);
1169 if (NT_SUCCESS(Status))
1170 {
1171 if (Face->style_name && Face->style_name[0] &&
1172 strcmp(Face->style_name, "Regular") != 0)
1173 {
1174 RtlInitAnsiString(&AnsiString, Face->style_name);
1175 Status = RtlAnsiStringToUnicodeString(&Entry->StyleName, &AnsiString, TRUE);
1176 if (!NT_SUCCESS(Status))
1177 {
1178 RtlFreeUnicodeString(&Entry->FaceName);
1179 }
1180 }
1181 else
1182 {
1183 RtlInitUnicodeString(&Entry->StyleName, NULL);
1184 }
1185 }
1186 if (!NT_SUCCESS(Status))
1187 {
1188 if (PrivateEntry)
1189 {
1190 if (pLoadFont->PrivateEntry == PrivateEntry)
1191 {
1192 pLoadFont->PrivateEntry = NULL;
1193 }
1194 else
1195 {
1196 RemoveEntryList(&PrivateEntry->ListEntry);
1197 }
1198 ExFreePoolWithTag(PrivateEntry, TAG_FONT);
1199 }
1200 if (FontGDI->Filename)
1201 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1202 EngFreeMem(FontGDI);
1203 SharedFace_Release(SharedFace);
1204 ExFreePoolWithTag(Entry, TAG_FONT);
1205 return 0;
1206 }
1207
1208 os2_version = 0;
1209 IntLockFreeType();
1210 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
1211 if (pOS2)
1212 {
1213 os2_version = pOS2->version;
1214 os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
1215 os2_usWeightClass = pOS2->usWeightClass;
1216 }
1217 IntUnLockFreeType();
1218
1219 if (pOS2 && os2_version >= 1)
1220 {
1221 /* get charset and weight from OS/2 header */
1222
1223 /* Make sure we do not use this pointer anymore */
1224 pOS2 = NULL;
1225
1226 for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
1227 {
1228 if (os2_ulCodePageRange1 & (1 << BitIndex))
1229 {
1230 if (g_FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
1231 continue;
1232
1233 if ((CharSetIndex == -1 && CharSetCount == 0) ||
1234 CharSetIndex == CharSetCount)
1235 {
1236 FontGDI->CharSet = g_FontTci[BitIndex].ciCharset;
1237 }
1238
1239 ++CharSetCount;
1240 }
1241 }
1242
1243 /* set actual weight */
1244 FontGDI->OriginalWeight = os2_usWeightClass;
1245 }
1246 else
1247 {
1248 /* get charset from WinFNT header */
1249 IntLockFreeType();
1250 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
1251 if (!Error)
1252 {
1253 FontGDI->CharSet = WinFNT.charset;
1254 }
1255 IntUnLockFreeType();
1256 }
1257
1258 /* FIXME: CharSet is invalid on Marlett */
1259 if (RtlEqualUnicodeString(&Entry->FaceName, &g_MarlettW, TRUE))
1260 {
1261 FontGDI->CharSet = SYMBOL_CHARSET;
1262 }
1263
1264 ++FaceCount;
1265 DPRINT("Font loaded: %s (%s)\n",
1266 Face->family_name ? Face->family_name : "<NULL>",
1267 Face->style_name ? Face->style_name : "<NULL>");
1268 DPRINT("Num glyphs: %d\n", Face->num_glyphs);
1269 DPRINT("CharSet: %d\n", FontGDI->CharSet);
1270
1271 IntLockFreeType();
1272 IntRequestFontSize(NULL, FontGDI, 0, 0);
1273 IntUnLockFreeType();
1274
1275 /* Add this font resource to the font table */
1276 Entry->Font = FontGDI;
1277 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
1278
1279 if (Characteristics & FR_PRIVATE)
1280 {
1281 /* private font */
1282 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1283 IntLockProcessPrivateFonts(Win32Process);
1284 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
1285 IntUnLockProcessPrivateFonts(Win32Process);
1286 }
1287 else
1288 {
1289 /* global font */
1290 IntLockGlobalFonts();
1291 InsertTailList(&g_FontListHead, &Entry->ListEntry);
1292 IntUnLockGlobalFonts();
1293 }
1294
1295 if (FontIndex == -1)
1296 {
1297 if (FT_IS_SFNT(Face))
1298 {
1299 TT_Face TrueType = (TT_Face)Face;
1300 if (TrueType->ttc_header.count > 1)
1301 {
1302 FT_Long i;
1303 for (i = 1; i < TrueType->ttc_header.count; ++i)
1304 {
1305 FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
1306 }
1307 }
1308 }
1309 FontIndex = 0;
1310 }
1311
1312 if (CharSetIndex == -1)
1313 {
1314 INT i;
1315 USHORT NameLength = Entry->FaceName.Length;
1316
1317 if (Entry->StyleName.Length)
1318 NameLength += Entry->StyleName.Length + sizeof(WCHAR);
1319
1320 if (pLoadFont->RegValueName.Length == 0)
1321 {
1322 pValueName->Length = 0;
1323 pValueName->MaximumLength = NameLength + sizeof(WCHAR);
1324 pValueName->Buffer = ExAllocatePoolWithTag(PagedPool,
1325 pValueName->MaximumLength,
1326 TAG_USTR);
1327 pValueName->Buffer[0] = UNICODE_NULL;
1328 RtlAppendUnicodeStringToString(pValueName, &Entry->FaceName);
1329 }
1330 else
1331 {
1332 UNICODE_STRING NewString;
1333 USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + NameLength;
1334 NewString.Length = 0;
1335 NewString.MaximumLength = Length + sizeof(WCHAR);
1336 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1337 NewString.MaximumLength,
1338 TAG_USTR);
1339 NewString.Buffer[0] = UNICODE_NULL;
1340
1341 RtlAppendUnicodeStringToString(&NewString, pValueName);
1342 RtlAppendUnicodeToString(&NewString, L" & ");
1343 RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
1344
1345 RtlFreeUnicodeString(pValueName);
1346 *pValueName = NewString;
1347 }
1348 if (Entry->StyleName.Length)
1349 {
1350 RtlAppendUnicodeToString(pValueName, L" ");
1351 RtlAppendUnicodeStringToString(pValueName, &Entry->StyleName);
1352 }
1353
1354 for (i = 1; i < CharSetCount; ++i)
1355 {
1356 /* Do not count charsets towards 'faces' loaded */
1357 IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
1358 }
1359 }
1360
1361 return FaceCount; /* number of loaded faces */
1362 }
1363
1364 /*
1365 * IntGdiAddFontResource
1366 *
1367 * Adds the font resource from the specified file to the system.
1368 */
1369
1370 INT FASTCALL
1371 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
1372 {
1373 NTSTATUS Status;
1374 HANDLE FileHandle;
1375 PVOID Buffer = NULL;
1376 IO_STATUS_BLOCK Iosb;
1377 PVOID SectionObject;
1378 SIZE_T ViewSize = 0;
1379 LARGE_INTEGER SectionSize;
1380 OBJECT_ATTRIBUTES ObjectAttributes;
1381 GDI_LOAD_FONT LoadFont;
1382 INT FontCount;
1383 HANDLE KeyHandle;
1384 static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
1385
1386 /* Open the font file */
1387 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
1388 Status = ZwOpenFile(
1389 &FileHandle,
1390 FILE_GENERIC_READ | SYNCHRONIZE,
1391 &ObjectAttributes,
1392 &Iosb,
1393 FILE_SHARE_READ,
1394 FILE_SYNCHRONOUS_IO_NONALERT);
1395 if (!NT_SUCCESS(Status))
1396 {
1397 DPRINT("Could not load font file: %wZ\n", FileName);
1398 return 0;
1399 }
1400
1401 SectionSize.QuadPart = 0LL;
1402 Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
1403 NULL, &SectionSize, PAGE_READONLY,
1404 SEC_COMMIT, FileHandle, NULL);
1405 if (!NT_SUCCESS(Status))
1406 {
1407 DPRINT("Could not map file: %wZ\n", FileName);
1408 ZwClose(FileHandle);
1409 return 0;
1410 }
1411 ZwClose(FileHandle);
1412
1413 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
1414 if (!NT_SUCCESS(Status))
1415 {
1416 DPRINT("Could not map file: %wZ\n", FileName);
1417 ObDereferenceObject(SectionObject);
1418 return 0;
1419 }
1420
1421 LoadFont.pFileName = FileName;
1422 LoadFont.Memory = SharedMem_Create(Buffer, ViewSize, TRUE);
1423 LoadFont.Characteristics = Characteristics;
1424 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1425 LoadFont.IsTrueType = FALSE;
1426 LoadFont.PrivateEntry = NULL;
1427 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1428
1429 ObDereferenceObject(SectionObject);
1430
1431 /* Release our copy */
1432 IntLockFreeType();
1433 SharedMem_Release(LoadFont.Memory);
1434 IntUnLockFreeType();
1435
1436 if (FontCount > 0)
1437 {
1438 if (LoadFont.IsTrueType)
1439 {
1440 /* append " (TrueType)" */
1441 UNICODE_STRING NewString;
1442 USHORT Length;
1443
1444 Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length;
1445 NewString.Length = 0;
1446 NewString.MaximumLength = Length + sizeof(WCHAR);
1447 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1448 NewString.MaximumLength,
1449 TAG_USTR);
1450 NewString.Buffer[0] = UNICODE_NULL;
1451
1452 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
1453 RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
1454 RtlFreeUnicodeString(&LoadFont.RegValueName);
1455 LoadFont.RegValueName = NewString;
1456 }
1457
1458 /* registry */
1459 InitializeObjectAttributes(&ObjectAttributes, &g_FontRegPath,
1460 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1461 NULL, NULL);
1462 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
1463 if (NT_SUCCESS(Status))
1464 {
1465 SIZE_T DataSize;
1466 LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
1467 if (pFileName)
1468 {
1469 pFileName++;
1470 DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
1471 ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
1472 pFileName, DataSize);
1473 }
1474 ZwClose(KeyHandle);
1475 }
1476 }
1477 RtlFreeUnicodeString(&LoadFont.RegValueName);
1478
1479 return FontCount;
1480 }
1481
1482 HANDLE FASTCALL
1483 IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
1484 {
1485 GDI_LOAD_FONT LoadFont;
1486 FONT_ENTRY_COLL_MEM* EntryCollection;
1487 INT FaceCount;
1488 HANDLE Ret = 0;
1489
1490 PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
1491
1492 if (!BufferCopy)
1493 {
1494 *pNumAdded = 0;
1495 return NULL;
1496 }
1497 memcpy(BufferCopy, Buffer, dwSize);
1498
1499 LoadFont.pFileName = NULL;
1500 LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
1501 LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
1502 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1503 LoadFont.IsTrueType = FALSE;
1504 LoadFont.PrivateEntry = NULL;
1505 FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1506
1507 RtlFreeUnicodeString(&LoadFont.RegValueName);
1508
1509 /* Release our copy */
1510 IntLockFreeType();
1511 SharedMem_Release(LoadFont.Memory);
1512 IntUnLockFreeType();
1513
1514 if (FaceCount > 0)
1515 {
1516 EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
1517 if (EntryCollection)
1518 {
1519 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1520 EntryCollection->Entry = LoadFont.PrivateEntry;
1521 IntLockProcessPrivateFonts(Win32Process);
1522 EntryCollection->Handle = ULongToHandle(++Win32Process->PrivateMemFontHandleCount);
1523 InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
1524 IntUnLockProcessPrivateFonts(Win32Process);
1525 Ret = EntryCollection->Handle;
1526 }
1527 }
1528 *pNumAdded = FaceCount;
1529
1530 return Ret;
1531 }
1532
1533 // FIXME: Add RemoveFontResource
1534
1535 static VOID FASTCALL
1536 CleanupFontEntry(PFONT_ENTRY FontEntry)
1537 {
1538 PFONTGDI FontGDI = FontEntry->Font;
1539 PSHARED_FACE SharedFace = FontGDI->SharedFace;
1540
1541 if (FontGDI->Filename)
1542 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1543
1544 EngFreeMem(FontGDI);
1545 SharedFace_Release(SharedFace);
1546 ExFreePoolWithTag(FontEntry, TAG_FONT);
1547 }
1548
1549 VOID FASTCALL
1550 IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
1551 {
1552 PLIST_ENTRY Entry;
1553 PFONT_ENTRY_MEM FontEntry;
1554
1555 while (!IsListEmpty(&Head->ListEntry))
1556 {
1557 Entry = RemoveHeadList(&Head->ListEntry);
1558 FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
1559
1560 CleanupFontEntry(FontEntry->Entry);
1561 ExFreePoolWithTag(FontEntry, TAG_FONT);
1562 }
1563
1564 CleanupFontEntry(Head->Entry);
1565 ExFreePoolWithTag(Head, TAG_FONT);
1566 }
1567
1568 static VOID FASTCALL
1569 UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)
1570 {
1571 PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
1572 PLIST_ENTRY ListEntry;
1573 RemoveEntryList(&Collection->ListEntry);
1574
1575 do {
1576 /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
1577 RemoveEntryList(&FontMemEntry->Entry->ListEntry);
1578
1579 ListEntry = FontMemEntry->ListEntry.Flink;
1580 FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
1581
1582 } while (FontMemEntry != Collection->Entry);
1583 }
1584
1585 BOOL FASTCALL
1586 IntGdiRemoveFontMemResource(HANDLE hMMFont)
1587 {
1588 PLIST_ENTRY Entry;
1589 PFONT_ENTRY_COLL_MEM CurrentEntry;
1590 PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
1591 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1592
1593 IntLockProcessPrivateFonts(Win32Process);
1594 for (Entry = Win32Process->PrivateMemFontListHead.Flink;
1595 Entry != &Win32Process->PrivateMemFontListHead;
1596 Entry = Entry->Flink)
1597 {
1598 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1599
1600 if (CurrentEntry->Handle == hMMFont)
1601 {
1602 EntryCollection = CurrentEntry;
1603 UnlinkFontMemCollection(CurrentEntry);
1604 break;
1605 }
1606 }
1607 IntUnLockProcessPrivateFonts(Win32Process);
1608
1609 if (EntryCollection)
1610 {
1611 IntGdiCleanupMemEntry(EntryCollection->Entry);
1612 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1613 return TRUE;
1614 }
1615 return FALSE;
1616 }
1617
1618
1619 VOID FASTCALL
1620 IntGdiCleanupPrivateFontsForProcess(VOID)
1621 {
1622 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1623 PLIST_ENTRY Entry;
1624 PFONT_ENTRY_COLL_MEM EntryCollection;
1625
1626 DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
1627 do {
1628 Entry = NULL;
1629 EntryCollection = NULL;
1630
1631 IntLockProcessPrivateFonts(Win32Process);
1632 if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
1633 {
1634 Entry = Win32Process->PrivateMemFontListHead.Flink;
1635 EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1636 UnlinkFontMemCollection(EntryCollection);
1637 }
1638 IntUnLockProcessPrivateFonts(Win32Process);
1639
1640 if (EntryCollection)
1641 {
1642 IntGdiCleanupMemEntry(EntryCollection->Entry);
1643 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1644 }
1645 else
1646 {
1647 /* No Mem fonts anymore, see if we have any other private fonts left */
1648 Entry = NULL;
1649 IntLockProcessPrivateFonts(Win32Process);
1650 if (!IsListEmpty(&Win32Process->PrivateFontListHead))
1651 {
1652 Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
1653 }
1654 IntUnLockProcessPrivateFonts(Win32Process);
1655
1656 if (Entry)
1657 {
1658 CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
1659 }
1660 }
1661
1662 } while (Entry);
1663 }
1664
1665 BOOL FASTCALL
1666 IntIsFontRenderingEnabled(VOID)
1667 {
1668 return (gpsi->BitsPixel > 8) && g_RenderingEnabled;
1669 }
1670
1671 VOID FASTCALL
1672 IntEnableFontRendering(BOOL Enable)
1673 {
1674 g_RenderingEnabled = Enable;
1675 }
1676
1677 FT_Render_Mode FASTCALL
1678 IntGetFontRenderMode(LOGFONTW *logfont)
1679 {
1680 switch (logfont->lfQuality)
1681 {
1682 case ANTIALIASED_QUALITY:
1683 break;
1684 case NONANTIALIASED_QUALITY:
1685 return FT_RENDER_MODE_MONO;
1686 case DRAFT_QUALITY:
1687 return FT_RENDER_MODE_LIGHT;
1688 case CLEARTYPE_QUALITY:
1689 if (!gspv.bFontSmoothing)
1690 break;
1691 if (!gspv.uiFontSmoothingType)
1692 break;
1693 return FT_RENDER_MODE_LCD;
1694 }
1695 return FT_RENDER_MODE_NORMAL;
1696 }
1697
1698
1699 NTSTATUS FASTCALL
1700 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
1701 {
1702 PLFONT plfont;
1703 LOGFONTW *plf;
1704
1705 ASSERT(lf);
1706 plfont = LFONT_AllocFontWithHandle();
1707 if (!plfont)
1708 {
1709 return STATUS_NO_MEMORY;
1710 }
1711
1712 ExInitializePushLock(&plfont->lock);
1713 *NewFont = plfont->BaseObject.hHmgr;
1714 plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
1715 RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
1716 if (lf->lfEscapement != lf->lfOrientation)
1717 {
1718 /* This should really depend on whether GM_ADVANCED is set */
1719 plf->lfOrientation = plf->lfEscapement;
1720 }
1721 LFONT_UnlockFont(plfont);
1722
1723 return STATUS_SUCCESS;
1724 }
1725
1726 /*************************************************************************
1727 * TranslateCharsetInfo
1728 *
1729 * Fills a CHARSETINFO structure for a character set, code page, or
1730 * font. This allows making the correspondance between different labelings
1731 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
1732 * of the same encoding.
1733 *
1734 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
1735 * only one codepage should be set in *Src.
1736 *
1737 * RETURNS
1738 * TRUE on success, FALSE on failure.
1739 *
1740 */
1741 static BOOLEAN APIENTRY
1742 IntTranslateCharsetInfo(PDWORD Src, /* [in]
1743 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
1744 if flags == TCI_SRCCHARSET: a character set value
1745 if flags == TCI_SRCCODEPAGE: a code page value */
1746 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
1747 DWORD Flags /* [in] determines interpretation of lpSrc */)
1748 {
1749 int Index = 0;
1750
1751 switch (Flags)
1752 {
1753 case TCI_SRCFONTSIG:
1754 while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
1755 {
1756 Index++;
1757 }
1758 break;
1759 case TCI_SRCCODEPAGE:
1760 while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciACP)
1761 {
1762 Index++;
1763 }
1764 break;
1765 case TCI_SRCCHARSET:
1766 while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciCharset)
1767 {
1768 Index++;
1769 }
1770 break;
1771 case TCI_SRCLOCALE:
1772 UNIMPLEMENTED;
1773 return FALSE;
1774 default:
1775 return FALSE;
1776 }
1777
1778 if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == g_FontTci[Index].ciCharset)
1779 {
1780 return FALSE;
1781 }
1782
1783 RtlCopyMemory(Cs, &g_FontTci[Index], sizeof(CHARSETINFO));
1784
1785 return TRUE;
1786 }
1787
1788
1789 static BOOL face_has_symbol_charmap(FT_Face ft_face)
1790 {
1791 int i;
1792
1793 for(i = 0; i < ft_face->num_charmaps; i++)
1794 {
1795 if (ft_face->charmaps[i]->platform_id == TT_PLATFORM_MICROSOFT &&
1796 ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
1797 {
1798 return TRUE;
1799 }
1800 }
1801 return FALSE;
1802 }
1803
1804 static void FASTCALL
1805 FillTMEx(TEXTMETRICW *TM, PFONTGDI FontGDI,
1806 TT_OS2 *pOS2, TT_HoriHeader *pHori,
1807 FT_WinFNT_HeaderRec *pFNT, BOOL RealFont)
1808 {
1809 FT_Fixed XScale, YScale;
1810 int Ascent, Descent;
1811 FT_Face Face = FontGDI->SharedFace->Face;
1812
1813 ASSERT_FREETYPE_LOCK_HELD();
1814
1815 XScale = Face->size->metrics.x_scale;
1816 YScale = Face->size->metrics.y_scale;
1817
1818 if (pFNT)
1819 {
1820 TM->tmHeight = pFNT->pixel_height;
1821 TM->tmAscent = pFNT->ascent;
1822 TM->tmDescent = TM->tmHeight - TM->tmAscent;
1823 TM->tmInternalLeading = pFNT->internal_leading;
1824 TM->tmExternalLeading = pFNT->external_leading;
1825 TM->tmAveCharWidth = pFNT->avg_width;
1826 TM->tmMaxCharWidth = pFNT->max_width;
1827 TM->tmOverhang = 0;
1828 TM->tmDigitizedAspectX = pFNT->horizontal_resolution;
1829 TM->tmDigitizedAspectY = pFNT->vertical_resolution;
1830 TM->tmFirstChar = pFNT->first_char;
1831 TM->tmLastChar = pFNT->last_char;
1832 TM->tmDefaultChar = pFNT->default_char + pFNT->first_char;
1833 TM->tmBreakChar = pFNT->break_char + pFNT->first_char;
1834 TM->tmPitchAndFamily = pFNT->pitch_and_family;
1835 if (RealFont)
1836 {
1837 TM->tmWeight = FontGDI->OriginalWeight;
1838 TM->tmItalic = FontGDI->OriginalItalic;
1839 TM->tmUnderlined = pFNT->underline;
1840 TM->tmStruckOut = pFNT->strike_out;
1841 TM->tmCharSet = pFNT->charset;
1842 }
1843 else
1844 {
1845 TM->tmWeight = FontGDI->RequestWeight;
1846 TM->tmItalic = FontGDI->RequestItalic;
1847 TM->tmUnderlined = FontGDI->RequestUnderline;
1848 TM->tmStruckOut = FontGDI->RequestStrikeOut;
1849 TM->tmCharSet = FontGDI->CharSet;
1850 }
1851 return;
1852 }
1853
1854 if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
1855 {
1856 Ascent = pHori->Ascender;
1857 Descent = -pHori->Descender;
1858 }
1859 else
1860 {
1861 Ascent = pOS2->usWinAscent;
1862 Descent = pOS2->usWinDescent;
1863 }
1864
1865 if (FontGDI->Magic != FONTGDI_MAGIC)
1866 {
1867 IntRequestFontSize(NULL, FontGDI, 0, 0);
1868 }
1869 TM->tmAscent = FontGDI->tmAscent;
1870 TM->tmDescent = FontGDI->tmDescent;
1871 TM->tmHeight = TM->tmAscent + TM->tmDescent;
1872 TM->tmInternalLeading = FontGDI->tmInternalLeading;
1873
1874 /* MSDN says:
1875 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1876 */
1877 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
1878 - ((Ascent + Descent)
1879 - (pHori->Ascender - pHori->Descender)),
1880 YScale) + 32) >> 6);
1881
1882 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
1883 if (TM->tmAveCharWidth == 0)
1884 {
1885 TM->tmAveCharWidth = 1;
1886 }
1887
1888 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
1889 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
1890
1891 if (RealFont)
1892 {
1893 TM->tmWeight = FontGDI->OriginalWeight;
1894 }
1895 else
1896 {
1897 if (FontGDI->OriginalWeight != FW_DONTCARE &&
1898 FontGDI->OriginalWeight != FW_NORMAL)
1899 {
1900 TM->tmWeight = FontGDI->OriginalWeight;
1901 }
1902 else
1903 {
1904 TM->tmWeight = FontGDI->RequestWeight;
1905 }
1906 }
1907
1908 TM->tmOverhang = 0;
1909 TM->tmDigitizedAspectX = 96;
1910 TM->tmDigitizedAspectY = 96;
1911 if (face_has_symbol_charmap(Face) ||
1912 (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
1913 {
1914 USHORT cpOEM, cpAnsi;
1915
1916 EngGetCurrentCodePage(&cpOEM, &cpAnsi);
1917 TM->tmFirstChar = 0;
1918 switch(cpAnsi)
1919 {
1920 case 1257: /* Baltic */
1921 TM->tmLastChar = 0xf8fd;
1922 break;
1923 default:
1924 TM->tmLastChar = 0xf0ff;
1925 }
1926 TM->tmBreakChar = 0x20;
1927 TM->tmDefaultChar = 0x1f;
1928 }
1929 else
1930 {
1931 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
1932 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
1933
1934 if(pOS2->usFirstCharIndex <= 1)
1935 TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
1936 else if (pOS2->usFirstCharIndex > 0xff)
1937 TM->tmBreakChar = 0x20;
1938 else
1939 TM->tmBreakChar = pOS2->usFirstCharIndex;
1940 TM->tmDefaultChar = TM->tmBreakChar - 1;
1941 }
1942
1943 if (RealFont)
1944 {
1945 TM->tmItalic = FontGDI->OriginalItalic;
1946 TM->tmUnderlined = FALSE;
1947 TM->tmStruckOut = FALSE;
1948 }
1949 else
1950 {
1951 if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
1952 {
1953 TM->tmItalic = 0xFF;
1954 }
1955 else
1956 {
1957 TM->tmItalic = 0;
1958 }
1959 TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
1960 TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
1961 }
1962
1963 if (!FT_IS_FIXED_WIDTH(Face))
1964 {
1965 switch (pOS2->panose[PAN_PROPORTION_INDEX])
1966 {
1967 case PAN_PROP_MONOSPACED:
1968 TM->tmPitchAndFamily = 0;
1969 break;
1970 default:
1971 TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH;
1972 break;
1973 }
1974 }
1975 else
1976 {
1977 TM->tmPitchAndFamily = 0;
1978 }
1979
1980 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
1981 {
1982 case PAN_FAMILY_SCRIPT:
1983 TM->tmPitchAndFamily |= FF_SCRIPT;
1984 break;
1985 case PAN_FAMILY_DECORATIVE:
1986 TM->tmPitchAndFamily |= FF_DECORATIVE;
1987 break;
1988
1989 case PAN_ANY:
1990 case PAN_NO_FIT:
1991 case PAN_FAMILY_TEXT_DISPLAY:
1992 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
1993 /* Which is clearly not what the panose spec says. */
1994 if (TM->tmPitchAndFamily == 0) /* Fixed */
1995 {
1996 TM->tmPitchAndFamily = FF_MODERN;
1997 }
1998 else
1999 {
2000 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
2001 {
2002 case PAN_ANY:
2003 case PAN_NO_FIT:
2004 default:
2005 TM->tmPitchAndFamily |= FF_DONTCARE;
2006 break;
2007
2008 case PAN_SERIF_COVE:
2009 case PAN_SERIF_OBTUSE_COVE:
2010 case PAN_SERIF_SQUARE_COVE:
2011 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2012 case PAN_SERIF_SQUARE:
2013 case PAN_SERIF_THIN:
2014 case PAN_SERIF_BONE:
2015 case PAN_SERIF_EXAGGERATED:
2016 case PAN_SERIF_TRIANGLE:
2017 TM->tmPitchAndFamily |= FF_ROMAN;
2018 break;
2019
2020 case PAN_SERIF_NORMAL_SANS:
2021 case PAN_SERIF_OBTUSE_SANS:
2022 case PAN_SERIF_PERP_SANS:
2023 case PAN_SERIF_FLARED:
2024 case PAN_SERIF_ROUNDED:
2025 TM->tmPitchAndFamily |= FF_SWISS;
2026 break;
2027 }
2028 }
2029 break;
2030 default:
2031 TM->tmPitchAndFamily |= FF_DONTCARE;
2032 }
2033
2034 if (FT_IS_SCALABLE(Face))
2035 {
2036 TM->tmPitchAndFamily |= TMPF_VECTOR;
2037 }
2038 if (FT_IS_SFNT(Face))
2039 {
2040 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
2041 }
2042
2043 TM->tmCharSet = FontGDI->CharSet;
2044 }
2045
2046 static void FASTCALL
2047 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
2048 TT_OS2 *pOS2, TT_HoriHeader *pHori,
2049 FT_WinFNT_HeaderRec *pFNT)
2050 {
2051 FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
2052 }
2053
2054 static NTSTATUS
2055 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
2056 FT_UShort NameID, FT_UShort LangID);
2057
2058 typedef struct FONT_NAMES
2059 {
2060 UNICODE_STRING FamilyNameW; /* family name (TT_NAME_ID_FONT_FAMILY) */
2061 UNICODE_STRING FaceNameW; /* face name (TT_NAME_ID_FULL_NAME) */
2062 UNICODE_STRING StyleNameW; /* style name (TT_NAME_ID_FONT_SUBFAMILY) */
2063 UNICODE_STRING FullNameW; /* unique name (TT_NAME_ID_UNIQUE_ID) */
2064 ULONG OtmSize; /* size of OUTLINETEXTMETRICW with extra data */
2065 } FONT_NAMES, *LPFONT_NAMES;
2066
2067 static __inline void FASTCALL
2068 IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace)
2069 {
2070 ULONG OtmSize;
2071
2072 RtlInitUnicodeString(&Names->FamilyNameW, NULL);
2073 RtlInitUnicodeString(&Names->FaceNameW, NULL);
2074 RtlInitUnicodeString(&Names->StyleNameW, NULL);
2075 RtlInitUnicodeString(&Names->FullNameW, NULL);
2076
2077 /* family name */
2078 IntGetFontLocalizedName(&Names->FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
2079 /* face name */
2080 IntGetFontLocalizedName(&Names->FaceNameW, SharedFace, TT_NAME_ID_FULL_NAME, gusLanguageID);
2081 /* style name */
2082 IntGetFontLocalizedName(&Names->StyleNameW, SharedFace, TT_NAME_ID_FONT_SUBFAMILY, gusLanguageID);
2083 /* unique name (full name) */
2084 IntGetFontLocalizedName(&Names->FullNameW, SharedFace, TT_NAME_ID_UNIQUE_ID, gusLanguageID);
2085
2086 /* Calculate the size of OUTLINETEXTMETRICW with extra data */
2087 OtmSize = sizeof(OUTLINETEXTMETRICW) +
2088 Names->FamilyNameW.Length + sizeof(UNICODE_NULL) +
2089 Names->FaceNameW.Length + sizeof(UNICODE_NULL) +
2090 Names->StyleNameW.Length + sizeof(UNICODE_NULL) +
2091 Names->FullNameW.Length + sizeof(UNICODE_NULL);
2092 Names->OtmSize = OtmSize;
2093 }
2094
2095 static __inline SIZE_T FASTCALL
2096 IntStoreName(const UNICODE_STRING *pName, BYTE *pb)
2097 {
2098 RtlCopyMemory(pb, pName->Buffer, pName->Length);
2099 *(WCHAR *)&pb[pName->Length] = UNICODE_NULL;
2100 return pName->Length + sizeof(UNICODE_NULL);
2101 }
2102
2103 static __inline BYTE *FASTCALL
2104 IntStoreFontNames(const FONT_NAMES *Names, OUTLINETEXTMETRICW *Otm)
2105 {
2106 BYTE *pb = (BYTE *)Otm + sizeof(OUTLINETEXTMETRICW);
2107
2108 /* family name */
2109 Otm->otmpFamilyName = (LPSTR)(pb - (BYTE*) Otm);
2110 pb += IntStoreName(&Names->FamilyNameW, pb);
2111
2112 /* face name */
2113 Otm->otmpFaceName = (LPSTR)(pb - (BYTE*) Otm);
2114 pb += IntStoreName(&Names->FaceNameW, pb);
2115
2116 /* style name */
2117 Otm->otmpStyleName = (LPSTR)(pb - (BYTE*) Otm);
2118 pb += IntStoreName(&Names->StyleNameW, pb);
2119
2120 /* unique name (full name) */
2121 Otm->otmpFullName = (LPSTR)(pb - (BYTE*) Otm);
2122 pb += IntStoreName(&Names->FullNameW, pb);
2123
2124 return pb;
2125 }
2126
2127 static __inline void FASTCALL
2128 IntFreeFontNames(FONT_NAMES *Names)
2129 {
2130 RtlFreeUnicodeString(&Names->FamilyNameW);
2131 RtlFreeUnicodeString(&Names->FaceNameW);
2132 RtlFreeUnicodeString(&Names->StyleNameW);
2133 RtlFreeUnicodeString(&Names->FullNameW);
2134 }
2135
2136 /*************************************************************
2137 * IntGetOutlineTextMetrics
2138 *
2139 */
2140 INT FASTCALL
2141 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
2142 UINT Size,
2143 OUTLINETEXTMETRICW *Otm)
2144 {
2145 TT_OS2 *pOS2;
2146 TT_HoriHeader *pHori;
2147 TT_Postscript *pPost;
2148 FT_Fixed XScale, YScale;
2149 FT_WinFNT_HeaderRec WinFNT;
2150 FT_Error Error;
2151 BYTE *pb;
2152 FONT_NAMES FontNames;
2153 PSHARED_FACE SharedFace = FontGDI->SharedFace;
2154 PSHARED_FACE_CACHE Cache;
2155 FT_Face Face = SharedFace->Face;
2156
2157 if (PRIMARYLANGID(gusLanguageID) == LANG_ENGLISH)
2158 {
2159 Cache = &SharedFace->EnglishUS;
2160 }
2161 else
2162 {
2163 Cache = &SharedFace->UserLanguage;
2164 }
2165
2166 if (Cache->OutlineRequiredSize && Size < Cache->OutlineRequiredSize)
2167 {
2168 return Cache->OutlineRequiredSize;
2169 }
2170
2171 IntInitFontNames(&FontNames, SharedFace);
2172
2173 if (!Cache->OutlineRequiredSize)
2174 {
2175 Cache->OutlineRequiredSize = FontNames.OtmSize;
2176 }
2177
2178 if (Size < Cache->OutlineRequiredSize)
2179 {
2180 IntFreeFontNames(&FontNames);
2181 return Cache->OutlineRequiredSize;
2182 }
2183
2184 XScale = Face->size->metrics.x_scale;
2185 YScale = Face->size->metrics.y_scale;
2186
2187 IntLockFreeType();
2188
2189 pOS2 = FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
2190 if (NULL == pOS2)
2191 {
2192 IntUnLockFreeType();
2193 DPRINT1("Can't find OS/2 table - not TT font?\n");
2194 IntFreeFontNames(&FontNames);
2195 return 0;
2196 }
2197
2198 pHori = FT_Get_Sfnt_Table(Face, FT_SFNT_HHEA);
2199 if (NULL == pHori)
2200 {
2201 IntUnLockFreeType();
2202 DPRINT1("Can't find HHEA table - not TT font?\n");
2203 IntFreeFontNames(&FontNames);
2204 return 0;
2205 }
2206
2207 pPost = FT_Get_Sfnt_Table(Face, FT_SFNT_POST); /* We can live with this failing */
2208
2209 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
2210
2211 Otm->otmSize = Cache->OutlineRequiredSize;
2212
2213 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &WinFNT : 0);
2214
2215 Otm->otmFiller = 0;
2216 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2217 Otm->otmfsSelection = pOS2->fsSelection;
2218 Otm->otmfsType = pOS2->fsType;
2219 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2220 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2221 Otm->otmItalicAngle = 0; /* POST table */
2222 Otm->otmEMSquare = Face->units_per_EM;
2223
2224 #define SCALE_X(value) ((FT_MulFix((value), XScale) + 32) >> 6)
2225 #define SCALE_Y(value) ((FT_MulFix((value), YScale) + 32) >> 6)
2226
2227 Otm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
2228 Otm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
2229 Otm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
2230 Otm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
2231 Otm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
2232 Otm->otmrcFontBox.left = SCALE_X(Face->bbox.xMin);
2233 Otm->otmrcFontBox.right = SCALE_X(Face->bbox.xMax);
2234 Otm->otmrcFontBox.top = SCALE_Y(Face->bbox.yMax);
2235 Otm->otmrcFontBox.bottom = SCALE_Y(Face->bbox.yMin);
2236 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
2237 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
2238 Otm->otmMacLineGap = Otm->otmLineGap;
2239 Otm->otmusMinimumPPEM = 0; /* TT Header */
2240 Otm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
2241 Otm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
2242 Otm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
2243 Otm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
2244 Otm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
2245 Otm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
2246 Otm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
2247 Otm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
2248 Otm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
2249 Otm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
2250
2251 if (!pPost)
2252 {
2253 Otm->otmsUnderscoreSize = 0;
2254 Otm->otmsUnderscorePosition = 0;
2255 }
2256 else
2257 {
2258 Otm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
2259 Otm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
2260 }
2261
2262 #undef SCALE_X
2263 #undef SCALE_Y
2264
2265 IntUnLockFreeType();
2266
2267 pb = IntStoreFontNames(&FontNames, Otm);
2268 ASSERT(pb - (BYTE*)Otm == Cache->OutlineRequiredSize);
2269
2270 IntFreeFontNames(&FontNames);
2271
2272 return Cache->OutlineRequiredSize;
2273 }
2274
2275 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
2276 static BYTE
2277 CharSetFromLangID(LANGID LangID)
2278 {
2279 /* FIXME: Add more and fix if wrong */
2280 switch (PRIMARYLANGID(LangID))
2281 {
2282 case LANG_CHINESE:
2283 switch (SUBLANGID(LangID))
2284 {
2285 case SUBLANG_CHINESE_TRADITIONAL:
2286 return CHINESEBIG5_CHARSET;
2287 case SUBLANG_CHINESE_SIMPLIFIED:
2288 default:
2289 break;
2290 }
2291 return GB2312_CHARSET;
2292
2293 case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
2294 case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
2295 return EASTEUROPE_CHARSET;
2296
2297 case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
2298 case LANG_SERBIAN: case LANG_UKRAINIAN:
2299 return RUSSIAN_CHARSET;
2300
2301 case LANG_ARABIC: return ARABIC_CHARSET;
2302 case LANG_GREEK: return GREEK_CHARSET;
2303 case LANG_HEBREW: return HEBREW_CHARSET;
2304 case LANG_JAPANESE: return SHIFTJIS_CHARSET;
2305 case LANG_KOREAN: return JOHAB_CHARSET;
2306 case LANG_TURKISH: return TURKISH_CHARSET;
2307 case LANG_THAI: return THAI_CHARSET;
2308 case LANG_LATVIAN: return BALTIC_CHARSET;
2309 case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
2310
2311 case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
2312 case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
2313 case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
2314 case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
2315 case LANG_SWEDISH: default:
2316 return ANSI_CHARSET;
2317 }
2318 }
2319
2320 static void
2321 SwapEndian(LPVOID pvData, DWORD Size)
2322 {
2323 BYTE b, *pb = pvData;
2324 Size /= 2;
2325 while (Size-- > 0)
2326 {
2327 b = pb[0];
2328 pb[0] = pb[1];
2329 pb[1] = b;
2330 ++pb; ++pb;
2331 }
2332 }
2333
2334 static NTSTATUS
2335 DuplicateUnicodeString(PUNICODE_STRING Source, PUNICODE_STRING Destination)
2336 {
2337 NTSTATUS Status = STATUS_NO_MEMORY;
2338 UNICODE_STRING Tmp;
2339
2340 Tmp.Buffer = ExAllocatePoolWithTag(PagedPool, Source->MaximumLength, TAG_USTR);
2341 if (Tmp.Buffer)
2342 {
2343 Tmp.MaximumLength = Source->MaximumLength;
2344 Tmp.Length = 0;
2345 RtlCopyUnicodeString(&Tmp, Source);
2346
2347 Destination->MaximumLength = Tmp.MaximumLength;
2348 Destination->Length = Tmp.Length;
2349 Destination->Buffer = Tmp.Buffer;
2350
2351 Status = STATUS_SUCCESS;
2352 }
2353
2354 return Status;
2355 }
2356
2357 static NTSTATUS
2358 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
2359 FT_UShort NameID, FT_UShort LangID)
2360 {
2361 FT_SfntName Name;
2362 INT i, Count, BestIndex, Score, BestScore;
2363 FT_Error Error;
2364 NTSTATUS Status = STATUS_NOT_FOUND;
2365 ANSI_STRING AnsiName;
2366 PSHARED_FACE_CACHE Cache;
2367 FT_Face Face = SharedFace->Face;
2368
2369 RtlFreeUnicodeString(pNameW);
2370
2371 /* select cache */
2372 if (PRIMARYLANGID(LangID) == LANG_ENGLISH)
2373 {
2374 Cache = &SharedFace->EnglishUS;
2375 }
2376 else
2377 {
2378 Cache = &SharedFace->UserLanguage;
2379 }
2380
2381 /* use cache if available */
2382 if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer)
2383 {
2384 return DuplicateUnicodeString(&Cache->FontFamily, pNameW);
2385 }
2386 if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer)
2387 {
2388 return DuplicateUnicodeString(&Cache->FullName, pNameW);
2389 }
2390
2391 BestIndex = -1;
2392 BestScore = 0;
2393
2394 Count = FT_Get_Sfnt_Name_Count(Face);
2395 for (i = 0; i < Count; ++i)
2396 {
2397 Error = FT_Get_Sfnt_Name(Face, i, &Name);
2398 if (Error)
2399 {
2400 continue; /* failure */
2401 }
2402
2403 if (Name.name_id != NameID)
2404 {
2405 continue; /* mismatched */
2406 }
2407
2408 if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
2409 (Name.encoding_id != TT_MS_ID_UNICODE_CS &&
2410 Name.encoding_id != TT_MS_ID_SYMBOL_CS))
2411 {
2412 continue; /* not Microsoft Unicode name */
2413 }
2414
2415 if (Name.string == NULL || Name.string_len == 0 ||
2416 (Name.string[0] == 0 && Name.string[1] == 0))
2417 {
2418 continue; /* invalid string */
2419 }
2420
2421 if (Name.language_id == LangID)
2422 {
2423 Score = 30;
2424 BestIndex = i;
2425 break; /* best match */
2426 }
2427 else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID))
2428 {
2429 Score = 20;
2430 }
2431 else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH)
2432 {
2433 Score = 10;
2434 }
2435 else
2436 {
2437 Score = 0;
2438 }
2439
2440 if (Score > BestScore)
2441 {
2442 BestScore = Score;
2443 BestIndex = i;
2444 }
2445 }
2446
2447 if (BestIndex >= 0)
2448 {
2449 /* store the best name */
2450 Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
2451 if (!Error)
2452 {
2453 /* NOTE: Name.string is not null-terminated */
2454 UNICODE_STRING Tmp;
2455 Tmp.Buffer = (PWCH)Name.string;
2456 Tmp.Length = Tmp.MaximumLength = Name.string_len;
2457
2458 pNameW->Length = 0;
2459 pNameW->MaximumLength = Name.string_len + sizeof(WCHAR);
2460 pNameW->Buffer = ExAllocatePoolWithTag(PagedPool, pNameW->MaximumLength, TAG_USTR);
2461
2462 if (pNameW->Buffer)
2463 {
2464 Status = RtlAppendUnicodeStringToString(pNameW, &Tmp);
2465 if (Status == STATUS_SUCCESS)
2466 {
2467 /* Convert UTF-16 big endian to little endian */
2468 SwapEndian(pNameW->Buffer, pNameW->Length);
2469 }
2470 }
2471 else
2472 {
2473 Status = STATUS_INSUFFICIENT_RESOURCES;
2474 }
2475 }
2476 }
2477
2478 if (!NT_SUCCESS(Status))
2479 {
2480 /* defaulted */
2481 if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
2482 {
2483 RtlInitAnsiString(&AnsiName, Face->style_name);
2484 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2485 }
2486 else
2487 {
2488 RtlInitAnsiString(&AnsiName, Face->family_name);
2489 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2490 }
2491 }
2492
2493 if (NT_SUCCESS(Status))
2494 {
2495 /* make cache */
2496 if (NameID == TT_NAME_ID_FONT_FAMILY)
2497 {
2498 ASSERT_FREETYPE_LOCK_NOT_HELD();
2499 IntLockFreeType();
2500 if (!Cache->FontFamily.Buffer)
2501 DuplicateUnicodeString(pNameW, &Cache->FontFamily);
2502 IntUnLockFreeType();
2503 }
2504 else if (NameID == TT_NAME_ID_FULL_NAME)
2505 {
2506 ASSERT_FREETYPE_LOCK_NOT_HELD();
2507 IntLockFreeType();
2508 if (!Cache->FullName.Buffer)
2509 DuplicateUnicodeString(pNameW, &Cache->FullName);
2510 IntUnLockFreeType();
2511 }
2512 }
2513
2514 return Status;
2515 }
2516
2517 static void FASTCALL
2518 FontFamilyFillInfo(PFONTFAMILYINFO Info, LPCWSTR FaceName,
2519 LPCWSTR FullName, PFONTGDI FontGDI)
2520 {
2521 ANSI_STRING StyleA;
2522 UNICODE_STRING StyleW;
2523 TT_OS2 *pOS2;
2524 FONTSIGNATURE fs;
2525 CHARSETINFO CharSetInfo;
2526 unsigned i, Size;
2527 OUTLINETEXTMETRICW *Otm;
2528 LOGFONTW *Lf;
2529 TEXTMETRICW *TM;
2530 NEWTEXTMETRICW *Ntm;
2531 DWORD fs0;
2532 NTSTATUS status;
2533 PSHARED_FACE SharedFace = FontGDI->SharedFace;
2534 FT_Face Face = SharedFace->Face;
2535 UNICODE_STRING NameW;
2536
2537 RtlInitUnicodeString(&NameW, NULL);
2538 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
2539 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2540 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2541 if (!Otm)
2542 {
2543 return;
2544 }
2545 Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2546 if (!Size)
2547 {
2548 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2549 return;
2550 }
2551
2552 Lf = &Info->EnumLogFontEx.elfLogFont;
2553 TM = &Otm->otmTextMetrics;
2554
2555 Lf->lfHeight = TM->tmHeight;
2556 Lf->lfWidth = TM->tmAveCharWidth;
2557 Lf->lfWeight = TM->tmWeight;
2558 Lf->lfItalic = TM->tmItalic;
2559 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
2560 Lf->lfCharSet = TM->tmCharSet;
2561 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
2562 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
2563 Lf->lfQuality = PROOF_QUALITY;
2564
2565 Ntm = &Info->NewTextMetricEx.ntmTm;
2566 Ntm->tmHeight = TM->tmHeight;
2567 Ntm->tmAscent = TM->tmAscent;
2568 Ntm->tmDescent = TM->tmDescent;
2569 Ntm->tmInternalLeading = TM->tmInternalLeading;
2570 Ntm->tmExternalLeading = TM->tmExternalLeading;
2571 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
2572 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
2573 Ntm->tmWeight = TM->tmWeight;
2574 Ntm->tmOverhang = TM->tmOverhang;
2575 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
2576 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
2577 Ntm->tmFirstChar = TM->tmFirstChar;
2578 Ntm->tmLastChar = TM->tmLastChar;
2579 Ntm->tmDefaultChar = TM->tmDefaultChar;
2580 Ntm->tmBreakChar = TM->tmBreakChar;
2581 Ntm->tmItalic = TM->tmItalic;
2582 Ntm->tmUnderlined = TM->tmUnderlined;
2583 Ntm->tmStruckOut = TM->tmStruckOut;
2584 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
2585 Ntm->tmCharSet = TM->tmCharSet;
2586 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
2587
2588 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
2589
2590 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
2591
2592 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
2593 ? TRUETYPE_FONTTYPE : 0);
2594
2595 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
2596 Info->FontType |= RASTER_FONTTYPE;
2597
2598
2599 /* face name */
2600 if (!FaceName)
2601 FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
2602
2603 RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
2604
2605 /* full name */
2606 if (!FullName)
2607 FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName);
2608
2609 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2610 sizeof(Info->EnumLogFontEx.elfFullName),
2611 FullName);
2612
2613 RtlInitAnsiString(&StyleA, Face->style_name);
2614 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
2615 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
2616 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
2617 if (!NT_SUCCESS(status))
2618 {
2619 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2620 return;
2621 }
2622 Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
2623
2624 IntLockFreeType();
2625 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2626
2627 if (!pOS2)
2628 {
2629 IntUnLockFreeType();
2630 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2631 return;
2632 }
2633
2634 Ntm->ntmSizeEM = Otm->otmEMSquare;
2635 Ntm->ntmCellHeight = pOS2->usWinAscent + pOS2->usWinDescent;
2636 Ntm->ntmAvgWidth = 0;
2637
2638 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2639
2640 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2641 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2642 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2643 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2644 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2645 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2646
2647 if (0 == pOS2->version)
2648 {
2649 FT_UInt Dummy;
2650
2651 if (FT_Get_First_Char(Face, &Dummy) < 0x100)
2652 fs.fsCsb[0] |= FS_LATIN1;
2653 else
2654 fs.fsCsb[0] |= FS_SYMBOL;
2655 }
2656 IntUnLockFreeType();
2657
2658 if (fs.fsCsb[0] == 0)
2659 {
2660 /* Let's see if we can find any interesting cmaps */
2661 for (i = 0; i < (UINT)Face->num_charmaps; i++)
2662 {
2663 switch (Face->charmaps[i]->encoding)
2664 {
2665 case FT_ENCODING_UNICODE:
2666 case FT_ENCODING_APPLE_ROMAN:
2667 fs.fsCsb[0] |= FS_LATIN1;
2668 break;
2669 case FT_ENCODING_MS_SYMBOL:
2670 fs.fsCsb[0] |= FS_SYMBOL;
2671 break;
2672 default:
2673 break;
2674 }
2675 }
2676 }
2677
2678 for (i = 0; i < MAXTCIINDEX; i++)
2679 {
2680 fs0 = 1L << i;
2681 if (fs.fsCsb[0] & fs0)
2682 {
2683 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
2684 {
2685 CharSetInfo.ciCharset = DEFAULT_CHARSET;
2686 }
2687 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
2688 {
2689 if (g_ElfScripts[i])
2690 wcscpy(Info->EnumLogFontEx.elfScript, g_ElfScripts[i]);
2691 else
2692 {
2693 DPRINT1("Unknown elfscript for bit %u\n", i);
2694 }
2695 }
2696 }
2697 }
2698 Info->NewTextMetricEx.ntmFontSig = fs;
2699 }
2700
2701 static BOOLEAN FASTCALL
2702 GetFontFamilyInfoForList(const LOGFONTW *LogFont,
2703 PFONTFAMILYINFO Info,
2704 LPCWSTR NominalName,
2705 LONG *pCount,
2706 LONG MaxCount,
2707 PLIST_ENTRY Head)
2708 {
2709 PLIST_ENTRY Entry;
2710 PFONT_ENTRY CurrentEntry;
2711 FONTGDI *FontGDI;
2712 FONTFAMILYINFO InfoEntry;
2713 LONG Count = *pCount;
2714
2715 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
2716 {
2717 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2718 FontGDI = CurrentEntry->Font;
2719 ASSERT(FontGDI);
2720
2721 if (LogFont->lfCharSet != DEFAULT_CHARSET &&
2722 LogFont->lfCharSet != FontGDI->CharSet)
2723 {
2724 continue; /* charset mismatch */
2725 }
2726
2727 /* get one info entry */
2728 FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
2729
2730 if (LogFont->lfFaceName[0] != UNICODE_NULL)
2731 {
2732 /* check name */
2733 if (_wcsnicmp(LogFont->lfFaceName,
2734 InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
2735 RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0 &&
2736 _wcsnicmp(LogFont->lfFaceName,
2737 InfoEntry.EnumLogFontEx.elfFullName,
2738 RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0)
2739 {
2740 continue;
2741 }
2742 }
2743
2744 if (NominalName)
2745 {
2746 /* store the nominal name */
2747 RtlStringCbCopyW(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
2748 sizeof(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName),
2749 NominalName);
2750 }
2751
2752 /* store one entry to Info */
2753 if (0 <= Count && Count < MaxCount)
2754 {
2755 RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
2756 }
2757 Count++;
2758 }
2759
2760 *pCount = Count;
2761
2762 return TRUE;
2763 }
2764
2765 static BOOLEAN FASTCALL
2766 GetFontFamilyInfoForSubstitutes(const LOGFONTW *LogFont,
2767 PFONTFAMILYINFO Info,
2768 LONG *pCount,
2769 LONG MaxCount)
2770 {
2771 PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead;
2772 PFONTSUBST_ENTRY pCurrentEntry;
2773 PUNICODE_STRING pFromW, pToW;
2774 LOGFONTW lf = *LogFont;
2775 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
2776
2777 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
2778 {
2779 pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
2780
2781 pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
2782 if (LogFont->lfFaceName[0] != UNICODE_NULL)
2783 {
2784 /* check name */
2785 if (_wcsicmp(LogFont->lfFaceName, pFromW->Buffer) != 0)
2786 continue; /* mismatch */
2787 }
2788
2789 pToW = &pCurrentEntry->FontNames[FONTSUBST_TO];
2790 if (RtlEqualUnicodeString(pFromW, pToW, TRUE) &&
2791 pCurrentEntry->CharSets[FONTSUBST_FROM] ==
2792 pCurrentEntry->CharSets[FONTSUBST_TO])
2793 {
2794 /* identical mapping */
2795 continue;
2796 }
2797
2798 /* substitute and get the real name */
2799 IntUnicodeStringToBuffer(lf.lfFaceName, sizeof(lf.lfFaceName), pFromW);
2800 SubstituteFontRecurse(&lf);
2801 if (LogFont->lfCharSet != DEFAULT_CHARSET && LogFont->lfCharSet != lf.lfCharSet)
2802 continue;
2803
2804 /* search in global fonts */
2805 IntLockGlobalFonts();
2806 GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount, &g_FontListHead);
2807 IntUnLockGlobalFonts();
2808
2809 /* search in private fonts */
2810 IntLockProcessPrivateFonts(Win32Process);
2811 GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount,
2812 &Win32Process->PrivateFontListHead);
2813 IntUnLockProcessPrivateFonts(Win32Process);
2814
2815 if (LogFont->lfFaceName[0] != UNICODE_NULL)
2816 {
2817 /* it's already matched to the exact name and charset if the name
2818 was specified at here, then so don't scan more for another name */
2819 break;
2820 }
2821 }
2822
2823 return TRUE;
2824 }
2825
2826 BOOL
2827 FASTCALL
2828 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
2829 {
2830 if ( lprs )
2831 {
2832 lprs->nSize = sizeof(RASTERIZER_STATUS);
2833 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
2834 lprs->nLanguageID = gusLanguageID;
2835 return TRUE;
2836 }
2837 EngSetLastError(ERROR_INVALID_PARAMETER);
2838 return FALSE;
2839 }
2840
2841 static
2842 BOOL
2843 SameScaleMatrix(
2844 PMATRIX pmx1,
2845 PMATRIX pmx2)
2846 {
2847 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
2848 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
2849 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
2850 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
2851 }
2852
2853 FT_BitmapGlyph APIENTRY
2854 ftGdiGlyphCacheGet(
2855 FT_Face Face,
2856 INT GlyphIndex,
2857 INT Height,
2858 INT Width,
2859 INT Escapement,
2860 FT_Render_Mode RenderMode,
2861 PMATRIX pmx)
2862 {
2863 PLIST_ENTRY CurrentEntry;
2864 PFONT_CACHE_ENTRY FontEntry;
2865
2866 ASSERT_FREETYPE_LOCK_HELD();
2867
2868 for (CurrentEntry = g_FontCacheListHead.Flink;
2869 CurrentEntry != &g_FontCacheListHead;
2870 CurrentEntry = CurrentEntry->Flink)
2871 {
2872 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
2873 if ((FontEntry->Face == Face) &&
2874 (FontEntry->GlyphIndex == GlyphIndex) &&
2875 (FontEntry->Height == Height) &&
2876 (FontEntry->Width == Width) &&
2877 (FontEntry->Escapement == Escapement) &&
2878 (FontEntry->RenderMode == RenderMode) &&
2879 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2880 break;
2881 }
2882
2883 if (CurrentEntry == &g_FontCacheListHead)
2884 {
2885 return NULL;
2886 }
2887
2888 RemoveEntryList(CurrentEntry);
2889 InsertHeadList(&g_FontCacheListHead, CurrentEntry);
2890 return FontEntry->BitmapGlyph;
2891 }
2892
2893 /* no cache */
2894 FT_BitmapGlyph APIENTRY
2895 ftGdiGlyphSet(
2896 FT_Face Face,
2897 FT_GlyphSlot GlyphSlot,
2898 FT_Render_Mode RenderMode)
2899 {
2900 FT_Glyph Glyph;
2901 INT error;
2902 FT_Bitmap AlignedBitmap;
2903 FT_BitmapGlyph BitmapGlyph;
2904
2905 error = FT_Get_Glyph(GlyphSlot, &Glyph);
2906 if (error)
2907 {
2908 DPRINT1("Failure getting glyph.\n");
2909 return NULL;
2910 }
2911
2912 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2913 if (error)
2914 {
2915 FT_Done_Glyph(Glyph);
2916 DPRINT1("Failure rendering glyph.\n");
2917 return NULL;
2918 }
2919
2920 BitmapGlyph = (FT_BitmapGlyph)Glyph;
2921 FT_Bitmap_New(&AlignedBitmap);
2922 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2923 {
2924 DPRINT1("Conversion failed\n");
2925 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2926 return NULL;
2927 }
2928
2929 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2930 BitmapGlyph->bitmap = AlignedBitmap;
2931
2932 return BitmapGlyph;
2933 }
2934
2935 FT_BitmapGlyph APIENTRY
2936 ftGdiGlyphCacheSet(
2937 FT_Face Face,
2938 INT GlyphIndex,
2939 INT Height,
2940 INT Width,
2941 INT Escapement,
2942 PMATRIX pmx,
2943 FT_GlyphSlot GlyphSlot,
2944 FT_Render_Mode RenderMode)
2945 {
2946 FT_Glyph GlyphCopy;
2947 INT error;
2948 PFONT_CACHE_ENTRY NewEntry;
2949 FT_Bitmap AlignedBitmap;
2950 FT_BitmapGlyph BitmapGlyph;
2951
2952 ASSERT_FREETYPE_LOCK_HELD();
2953
2954 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2955 if (error)
2956 {
2957 DPRINT1("Failure caching glyph.\n");
2958 return NULL;
2959 };
2960
2961 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2962 if (error)
2963 {
2964 FT_Done_Glyph(GlyphCopy);
2965 DPRINT1("Failure rendering glyph.\n");
2966 return NULL;
2967 };
2968
2969 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
2970 if (!NewEntry)
2971 {
2972 DPRINT1("Alloc failure caching glyph.\n");
2973 FT_Done_Glyph(GlyphCopy);
2974 return NULL;
2975 }
2976
2977 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2978 FT_Bitmap_New(&AlignedBitmap);
2979 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2980 {
2981 DPRINT1("Conversion failed\n");
2982 ExFreePoolWithTag(NewEntry, TAG_FONT);
2983 FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
2984 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2985 return NULL;
2986 }
2987
2988 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2989 BitmapGlyph->bitmap = AlignedBitmap;
2990
2991 NewEntry->GlyphIndex = GlyphIndex;
2992 NewEntry->Face = Face;
2993 NewEntry->BitmapGlyph = BitmapGlyph;
2994 NewEntry->Height = Height;
2995 NewEntry->Width = Width;
2996 NewEntry->Escapement = Escapement;
2997 NewEntry->RenderMode = RenderMode;
2998 NewEntry->mxWorldToDevice = *pmx;
2999
3000 InsertHeadList(&g_FontCacheListHead, &NewEntry->ListEntry);
3001 if (++g_FontCacheNumEntries > MAX_FONT_CACHE)
3002 {
3003 NewEntry = CONTAINING_RECORD(g_FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
3004 RemoveCachedEntry(NewEntry);
3005 }
3006
3007 return BitmapGlyph;
3008 }
3009
3010
3011 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3012 {
3013 TTPOLYGONHEADER *pph;
3014 TTPOLYCURVE *ppc;
3015 int needed = 0, point = 0, contour, first_pt;
3016 unsigned int pph_start, cpfx;
3017 DWORD type;
3018
3019 for (contour = 0; contour < outline->n_contours; contour++)
3020 {
3021 /* Ignore contours containing one point */
3022 if (point == outline->contours[contour])
3023 {
3024 point++;
3025 continue;
3026 }
3027
3028 pph_start = needed;
3029 pph = (TTPOLYGONHEADER *)(buf + needed);
3030 first_pt = point;
3031 if (buf)
3032 {
3033 pph->dwType = TT_POLYGON_TYPE;
3034 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3035 }
3036 needed += sizeof(*pph);
3037 point++;
3038 while (point <= outline->contours[contour])
3039 {
3040 ppc = (TTPOLYCURVE *)(buf + needed);
3041 type = outline->tags[point] & FT_Curve_Tag_On ?
3042 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3043 cpfx = 0;
3044 do
3045 {
3046 if (buf)
3047 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3048 cpfx++;
3049 point++;
3050 } while (point <= outline->contours[contour] &&
3051 (outline->tags[point] & FT_Curve_Tag_On) ==
3052 (outline->tags[point-1] & FT_Curve_Tag_On));
3053 /* At the end of a contour Windows adds the start point, but
3054 only for Beziers */
3055 if (point > outline->contours[contour] &&
3056 !(outline->tags[point-1] & FT_Curve_Tag_On))
3057 {
3058 if (buf)
3059 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3060 cpfx++;
3061 }
3062 else if (point <= outline->contours[contour] &&
3063 outline->tags[point] & FT_Curve_Tag_On)
3064 {
3065 /* add closing pt for bezier */
3066 if (buf)
3067 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3068 cpfx++;
3069 point++;
3070 }
3071 if (buf)
3072 {
3073 ppc->wType = type;
3074 ppc->cpfx = cpfx;
3075 }
3076 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3077 }
3078 if (buf)
3079 pph->cb = needed - pph_start;
3080 }
3081 return needed;
3082 }
3083
3084 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3085 {
3086 /* Convert the quadratic Beziers to cubic Beziers.
3087 The parametric eqn for a cubic Bezier is, from PLRM:
3088 r(t) = at^3 + bt^2 + ct + r0
3089 with the control points:
3090 r1 = r0 + c/3
3091 r2 = r1 + (c + b)/3
3092 r3 = r0 + c + b + a
3093
3094 A quadratic Bezier has the form:
3095 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3096
3097 So equating powers of t leads to:
3098 r1 = 2/3 p1 + 1/3 p0
3099 r2 = 2/3 p1 + 1/3 p2
3100 and of course r0 = p0, r3 = p2
3101 */
3102 int contour, point = 0, first_pt;
3103 TTPOLYGONHEADER *pph;
3104 TTPOLYCURVE *ppc;
3105 DWORD pph_start, cpfx, type;
3106 FT_Vector cubic_control[4];
3107 unsigned int needed = 0;
3108
3109 for (contour = 0; contour < outline->n_contours; contour++)
3110 {
3111 pph_start = needed;
3112 pph = (TTPOLYGONHEADER *)(buf + needed);
3113 first_pt = point;
3114 if (buf)
3115 {
3116 pph->dwType = TT_POLYGON_TYPE;
3117 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3118 }
3119 needed += sizeof(*pph);
3120 point++;
3121 while (point <= outline->contours[contour])
3122 {
3123 ppc = (TTPOLYCURVE *)(buf + needed);
3124 type = outline->tags[point] & FT_Curve_Tag_On ?
3125 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3126 cpfx = 0;
3127 do
3128 {
3129 if (type == TT_PRIM_LINE)
3130 {
3131 if (buf)
3132 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3133 cpfx++;
3134 point++;
3135 }
3136 else
3137 {
3138 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3139 so cpfx = 3n */
3140
3141 /* FIXME: Possible optimization in endpoint calculation
3142 if there are two consecutive curves */
3143 cubic_control[0] = outline->points[point-1];
3144 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3145 {
3146 cubic_control[0].x += outline->points[point].x + 1;
3147 cubic_control[0].y += outline->points[point].y + 1;
3148 cubic_control[0].x >>= 1;
3149 cubic_control[0].y >>= 1;
3150 }
3151 if (point+1 > outline->contours[contour])
3152 cubic_control[3] = outline->points[first_pt];
3153 else
3154 {
3155 cubic_control[3] = outline->points[point+1];
3156 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3157 {
3158 cubic_control[3].x += outline->points[point].x + 1;
3159 cubic_control[3].y += outline->points[point].y + 1;
3160 cubic_control[3].x >>= 1;
3161 cubic_control[3].y >>= 1;
3162 }
3163 }
3164 /* r1 = 1/3 p0 + 2/3 p1
3165 r2 = 1/3 p2 + 2/3 p1 */
3166 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3167 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3168 cubic_control[2] = cubic_control[1];
3169 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3170 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3171 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3172 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3173 if (buf)
3174 {
3175 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3176 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3177 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3178 }
3179 cpfx += 3;
3180 point++;
3181 }
3182 } while (point <= outline->contours[contour] &&
3183 (outline->tags[point] & FT_Curve_Tag_On) ==
3184 (outline->tags[point-1] & FT_Curve_Tag_On));
3185 /* At the end of a contour Windows adds the start point,
3186 but only for Beziers and we've already done that.
3187 */
3188 if (point <= outline->contours[contour] &&
3189 outline->tags[point] & FT_Curve_Tag_On)
3190 {
3191 /* This is the closing pt of a bezier, but we've already
3192 added it, so just inc point and carry on */
3193 point++;
3194 }
3195 if (buf)
3196 {
3197 ppc->wType = type;
3198 ppc->cpfx = cpfx;
3199 }
3200 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3201 }
3202 if (buf)
3203 pph->cb = needed - pph_start;
3204 }
3205 return needed;
3206 }
3207
3208 static FT_Error
3209 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
3210 {
3211 FT_Error error;
3212 FT_Size_RequestRec req;
3213 FT_Face face = FontGDI->SharedFace->Face;
3214 TT_OS2 *pOS2;
3215 TT_HoriHeader *pHori;
3216 FT_WinFNT_HeaderRec WinFNT;
3217 LONG Ascent, Descent, Sum, EmHeight64;
3218
3219 lfWidth = abs(lfWidth);
3220 if (lfHeight == 0)
3221 {
3222 if (lfWidth == 0)
3223 {
3224 DPRINT("lfHeight and lfWidth are zero.\n");
3225 lfHeight = -16;
3226 }
3227 else
3228 {
3229 lfHeight = lfWidth;
3230 }
3231 }
3232
3233 if (lfHeight == -1)
3234 lfHeight = -2;
3235
3236 ASSERT_FREETYPE_LOCK_HELD();
3237 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
3238 pHori = (TT_HoriHeader *)FT_Get_Sfnt_Table(face, FT_SFNT_HHEA);
3239
3240 if (!pOS2 || !pHori)
3241 {
3242 error = FT_Get_WinFNT_Header(face, &WinFNT);
3243 if (error)
3244 {
3245 DPRINT1("%s: Failed to request font size.\n", face->family_name);
3246 ASSERT(FALSE);
3247 return error;
3248 }
3249
3250 FontGDI->tmHeight = WinFNT.pixel_height;
3251 FontGDI->tmAscent = WinFNT.ascent;
3252 FontGDI->tmDescent = FontGDI->tmHeight - FontGDI->tmAscent;
3253 FontGDI->tmInternalLeading = WinFNT.internal_leading;
3254 FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3255 FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3256 FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3257 FontGDI->Magic = FONTGDI_MAGIC;
3258
3259 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
3260 req.width = 0;
3261 req.height = (FT_Long)(FontGDI->EmHeight << 6);
3262 req.horiResolution = 0;
3263 req.vertResolution = 0;
3264 return FT_Request_Size(face, &req);
3265 }
3266
3267 /* See also: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fsselection */
3268 #define FM_SEL_USE_TYPO_METRICS 0x80
3269 if (lfHeight > 0)
3270 {
3271 /* case (A): lfHeight is positive */
3272 Sum = pOS2->usWinAscent + pOS2->usWinDescent;
3273 if (Sum == 0 || (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS))
3274 {
3275 Ascent = pHori->Ascender;
3276 Descent = -pHori->Descender;
3277 Sum = Ascent + Descent;
3278 }
3279 else
3280 {
3281 Ascent = pOS2->usWinAscent;
3282 Descent = pOS2->usWinDescent;
3283 }
3284
3285 FontGDI->tmAscent = FT_MulDiv(lfHeight, Ascent, Sum);
3286 FontGDI->tmDescent = FT_MulDiv(lfHeight, Descent, Sum);
3287 FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3288 FontGDI->tmInternalLeading = FontGDI->tmHeight - FT_MulDiv(lfHeight, face->units_per_EM, Sum);
3289 }
3290 else if (lfHeight < 0)
3291 {
3292 /* case (B): lfHeight is negative */
3293 if (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS)
3294 {
3295 FontGDI->tmAscent = FT_MulDiv(-lfHeight, pHori->Ascender, face->units_per_EM);
3296 FontGDI->tmDescent = FT_MulDiv(-lfHeight, -pHori->Descender, face->units_per_EM);
3297 }
3298 else
3299 {
3300 FontGDI->tmAscent = FT_MulDiv(-lfHeight, pOS2->usWinAscent, face->units_per_EM);
3301 FontGDI->tmDescent = FT_MulDiv(-lfHeight, pOS2->usWinDescent, face->units_per_EM);
3302 }
3303 FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3304 FontGDI->tmInternalLeading = FontGDI->tmHeight + lfHeight;
3305 }
3306 #undef FM_SEL_USE_TYPO_METRICS
3307
3308 FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3309 FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3310 FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3311 FontGDI->Magic = FONTGDI_MAGIC;
3312
3313 EmHeight64 = (FontGDI->EmHeight << 6);
3314
3315 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
3316 req.width = 0;
3317 req.height = EmHeight64;
3318 req.horiResolution = 0;
3319 req.vertResolution = 0;
3320 return FT_Request_Size(face, &req);
3321 }
3322
3323 BOOL
3324 FASTCALL
3325 TextIntUpdateSize(PDC dc,
3326 PTEXTOBJ TextObj,
3327 PFONTGDI FontGDI,
3328 BOOL bDoLock)
3329 {
3330 FT_Face face;
3331 INT error, n;
3332 FT_CharMap charmap, found;
3333 LOGFONTW *plf;
3334
3335 if (bDoLock)
3336 IntLockFreeType();
3337
3338 face = FontGDI->SharedFace->Face;
3339 if (face->charmap == NULL)
3340 {
3341 DPRINT("WARNING: No charmap selected!\n");
3342 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3343
3344 found = NULL;
3345 for (n = 0; n < face->num_charmaps; n++)
3346 {
3347 charmap = face->charmaps[n];
3348 if (charmap->encoding == FT_ENCODING_UNICODE)
3349 {
3350 found = charmap;
3351 break;
3352 }
3353 }
3354 if (!found)
3355 {
3356 for (n = 0; n < face->num_charmaps; n++)
3357 {
3358 charmap = face->charmaps[n];
3359 if (charmap->encoding == FT_ENCODING_MS_SYMBOL)
3360 {
3361 found = charmap;
3362 break;
3363 }
3364 }
3365 }
3366 if (!found)
3367 {
3368 DPRINT1("WARNING: Could not find desired charmap!\n");
3369 }
3370 else
3371 {
3372 DPRINT("Found charmap encoding: %i\n", found->encoding);
3373 error = FT_Set_Charmap(face, found);
3374 if (error)
3375 {
3376 DPRINT1("WARNING: Could not set the charmap!\n");
3377 }
3378 }
3379 }
3380
3381 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3382
3383 error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
3384
3385 if (bDoLock)
3386 IntUnLockFreeType();
3387
3388 if (error)
3389 {
3390 DPRINT1("Error in setting pixel sizes: %d\n", error);
3391 return FALSE;
3392 }
3393
3394 return TRUE;
3395 }
3396
3397 static inline FT_UInt FASTCALL
3398 get_glyph_index_symbol(FT_Face ft_face, UINT glyph)
3399 {
3400 FT_UInt ret;
3401
3402 if (glyph < 0x100) glyph += 0xf000;
3403 /* there are a number of old pre-Unicode "broken" TTFs, which
3404 do have symbols at U+00XX instead of U+f0XX */
3405 if (!(ret = FT_Get_Char_Index(ft_face, glyph)))
3406 ret = FT_Get_Char_Index(ft_face, glyph - 0xf000);
3407
3408 return ret;
3409 }
3410
3411 static inline FT_UInt FASTCALL
3412 get_glyph_index(FT_Face ft_face, UINT glyph)
3413 {
3414 FT_UInt ret;
3415
3416 if (face_has_symbol_charmap(ft_face))
3417 {
3418 ret = get_glyph_index_symbol(ft_face, glyph);
3419 if (ret != 0)
3420 return ret;
3421 }
3422
3423 return FT_Get_Char_Index(ft_face, glyph);
3424 }
3425
3426 static inline FT_UInt FASTCALL
3427 get_glyph_index_flagged(FT_Face face, FT_ULong code, DWORD indexed_flag, DWORD flags)
3428 {
3429 FT_UInt glyph_index;
3430 if (flags & indexed_flag)
3431 {
3432 glyph_index = code;
3433 }
3434 else
3435 {
3436 glyph_index = get_glyph_index(face, code);
3437 }
3438 return glyph_index;
3439 }
3440
3441 /*
3442 * Based on WineEngGetGlyphOutline
3443 *
3444 */
3445 ULONG
3446 FASTCALL
3447 ftGdiGetGlyphOutline(
3448 PDC dc,
3449 WCHAR wch,
3450 UINT iFormat,
3451 LPGLYPHMETRICS pgm,
3452 ULONG cjBuf,
3453 PVOID pvBuf,
3454 LPMAT2 pmat2,
3455 BOOL bIgnoreRotation)
3456 {
3457 PDC_ATTR pdcattr;
3458 PTEXTOBJ TextObj;
3459 PFONTGDI FontGDI;
3460 HFONT hFont = 0;
3461 GLYPHMETRICS gm;
3462 ULONG Size;
3463 FT_Face ft_face;
3464 FT_UInt glyph_index;
3465 DWORD width, height, pitch, needed = 0;
3466 FT_Bitmap ft_bitmap;
3467 FT_Error error;
3468 INT left, right, top = 0, bottom = 0;
3469 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3470 FLOATOBJ eM11, widthRatio, eTemp;
3471 FT_Matrix transMat = identityMat;
3472 BOOL needsTransform = FALSE;
3473 INT orientation;
3474 LONG aveWidth;
3475 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3476 OUTLINETEXTMETRICW *potm;
3477 XFORMOBJ xo;
3478 XFORML xform;
3479 LOGFONTW *plf;
3480
3481 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3482 cjBuf, pvBuf, pmat2);
3483
3484 pdcattr = dc->pdcattr;
3485
3486 XFORMOBJ_vInit(&xo, &dc->pdcattr->mxWorldToDevice);
3487 XFORMOBJ_iGetXform(&xo, &xform);
3488 FLOATOBJ_SetFloat(&eM11, xform.eM11);
3489
3490 hFont = pdcattr->hlfntNew;
3491 TextObj = RealizeFontInit(hFont);
3492
3493 if (!TextObj)
3494 {
3495 EngSetLastError(ERROR_INVALID_HANDLE);
3496 return GDI_ERROR;
3497 }
3498 FontGDI = ObjToGDI(TextObj->Font, FONT);
3499 ft_face = FontGDI->SharedFace->Face;
3500
3501 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3502 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3503 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3504
3505 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3506 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3507 if (!potm)
3508 {
3509 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3510 TEXTOBJ_UnlockText(TextObj);
3511 return GDI_ERROR;
3512 }
3513 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
3514 if (!Size)
3515 {
3516 /* FIXME: last error? */
3517 ExFreePoolWithTag(potm, GDITAG_TEXT);
3518 TEXTOBJ_UnlockText(TextObj);
3519 return GDI_ERROR;
3520 }
3521
3522 IntLockFreeType();
3523 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3524 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
3525
3526 TEXTOBJ_UnlockText(TextObj);
3527
3528 glyph_index = get_glyph_index_flagged(ft_face, wch, GGO_GLYPH_INDEX, iFormat);
3529 iFormat &= ~GGO_GLYPH_INDEX;
3530
3531 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3532 load_flags |= FT_LOAD_NO_BITMAP;
3533
3534 if (iFormat & GGO_UNHINTED)
3535 {
3536 load_flags |= FT_LOAD_NO_HINTING;
3537 iFormat &= ~GGO_UNHINTED;
3538 }
3539
3540 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3541 if (error)
3542 {
3543 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3544 IntUnLockFreeType();
3545 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3546 return GDI_ERROR;
3547 }
3548 IntUnLockFreeType();
3549
3550 FLOATOBJ_Set1(&widthRatio);
3551 if (aveWidth && potm)
3552 {
3553 // widthRatio = aveWidth * eM11 / potm->otmTextMetrics.tmAveCharWidth
3554 FLOATOBJ_SetLong(&widthRatio, aveWidth);
3555 FLOATOBJ_Mul(&widthRatio, &eM11);
3556 FLOATOBJ_DivLong(&widthRatio, potm->otmTextMetrics.tmAveCharWidth);
3557 }
3558
3559 //left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3560 FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiBearingX);
3561 FLOATOBJ_Mul(&eTemp, &widthRatio);
3562 left = FLOATOBJ_GetLong(&eTemp) & -64;
3563
3564 //right = (INT)((ft_face->glyph->metrics.horiBearingX +
3565 // ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3566 FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiBearingX * ft_face->glyph->metrics.width);
3567 FLOATOBJ_Mul(&eTemp, &widthRatio);
3568 FLOATOBJ_AddLong(&eTemp, 63);
3569 right = FLOATOBJ_GetLong(&eTemp) & -64;
3570
3571 //adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3572 FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiAdvance);
3573 FLOATOBJ_Mul(&eTemp, &widthRatio);
3574 FLOATOBJ_AddLong(&eTemp, 63);
3575 adv = FLOATOBJ_GetLong(&eTemp) >> 6;
3576
3577 lsb = left >> 6;
3578 bbx = (right - left) >> 6;
3579
3580 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3581
3582 IntLockFreeType();
3583
3584 /* Width scaling transform */
3585 if (!FLOATOBJ_Equal1(&widthRatio))
3586 {
3587 FT_Matrix scaleMat;
3588
3589 eTemp = widthRatio;
3590 FLOATOBJ_MulLong(&eTemp, 1 << 16);
3591
3592 scaleMat.xx = FLOATOBJ_GetLong(&eTemp);
3593 scaleMat.xy = 0;
3594 scaleMat.yx = 0;
3595 scaleMat.yy = INT_TO_FIXED(1);
3596 FT_Matrix_Multiply(&scaleMat, &transMat);
3597 needsTransform = TRUE;
3598 }
3599
3600 /* World transform */
3601 {
3602 FT_Matrix ftmatrix;
3603 PMATRIX pmx = DC_pmxWorldToDevice(dc);
3604
3605 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3606 FtMatrixFromMx(&ftmatrix, pmx);
3607
3608 if (memcmp(&ftmatrix, &identityMat, sizeof(identityMat)) != 0)
3609 {
3610 FT_Matrix_Multiply(&ftmatrix, &transMat);
3611 needsTransform = TRUE;
3612 }
3613 }
3614
3615 /* Rotation transform */
3616 if (orientation)
3617 {
3618 FT_Matrix rotationMat;
3619 DPRINT("Rotation Trans!\n");
3620 IntEscapeMatrix(&rotationMat, orientation);
3621 FT_Matrix_Multiply(&rotationMat, &transMat);
3622 needsTransform = TRUE;
3623 }
3624
3625 /* Extra transformation specified by caller */
3626 if (pmat2)
3627 {
3628 FT_Matrix extraMat;
3629 DPRINT("MAT2 Matrix Trans!\n");
3630 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
3631 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
3632 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
3633 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
3634 FT_Matrix_Multiply(&extraMat, &transMat);
3635 needsTransform = TRUE;
3636 }
3637
3638 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
3639
3640 if (!needsTransform)
3641 {
3642 DPRINT("No Need to be Transformed!\n");
3643 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3644 bottom = (ft_face->glyph->metrics.horiBearingY -
3645 ft_face->glyph->metrics.height) & -64;
3646 gm.gmCellIncX = adv;
3647 gm.gmCellIncY = 0;
3648 }
3649 else
3650 {
3651 INT xc, yc;
3652 FT_Vector vec;
3653 for (xc = 0; xc < 2; xc++)
3654 {
3655 for (yc = 0; yc < 2; yc++)
3656 {
3657 vec.x = (ft_face->glyph->metrics.horiBearingX +
3658 xc * ft_face->glyph->metrics.width);
3659 vec.y = ft_face->glyph->metrics.horiBearingY -
3660 yc * ft_face->glyph->metrics.height;
3661 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
3662 FT_Vector_Transform(&vec, &transMat);
3663 if (xc == 0 && yc == 0)
3664 {
3665 left = right = vec.x;
3666 top = bottom = vec.y;
3667 }
3668 else
3669 {
3670 if (vec.x < left) left = vec.x;
3671 else if (vec.x > right) right = vec.x;
3672 if (vec.y < bottom) bottom = vec.y;
3673 else if (vec.y > top) top = vec.y;
3674 }
3675 }
3676 }
3677 left = left & -64;
3678 right = (right + 63) & -64;
3679 bottom = bottom & -64;
3680 top = (top + 63) & -64;
3681
3682 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3683 vec.x = ft_face->glyph->metrics.horiAdvance;
3684 vec.y = 0;
3685 FT_Vector_Transform(&vec, &transMat);
3686 gm.gmCellIncX = (vec.x+63) >> 6;
3687 gm.gmCellIncY = -((vec.y+63) >> 6);
3688 }
3689 gm.gmBlackBoxX = (right - left) >> 6;
3690 gm.gmBlackBoxY = (top - bottom) >> 6;
3691 gm.gmptGlyphOrigin.x = left >> 6;
3692 gm.gmptGlyphOrigin.y = top >> 6;
3693
3694 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
3695 gm.gmCellIncX, gm.gmCellIncY,
3696 gm.gmBlackBoxX, gm.gmBlackBoxY,
3697 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
3698
3699 IntUnLockFreeType();
3700
3701
3702 if (iFormat == GGO_METRICS)
3703 {
3704 DPRINT("GGO_METRICS Exit!\n");
3705 *pgm = gm;
3706 return 1; /* FIXME */
3707 }
3708
3709 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
3710 {
3711 DPRINT1("Loaded a bitmap\n");
3712 return GDI_ERROR;
3713 }
3714
3715 switch (iFormat)
3716 {
3717 case GGO_BITMAP:
3718 {
3719 width = gm.gmBlackBoxX;
3720 height = gm.gmBlackBoxY;
3721 pitch = ((width + 31) >> 5) << 2;
3722 needed = pitch * height;
3723
3724 if (!pvBuf || !cjBuf) break;
3725 if (!needed) return GDI_ERROR; /* empty glyph */
3726 if (needed > cjBuf)
3727 return GDI_ERROR;
3728
3729 switch (ft_face->glyph->format)
3730 {
3731 case ft_glyph_format_bitmap:
3732 {
3733 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3734 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
3735 INT h = min( height, ft_face->glyph->bitmap.rows );
3736 while (h--)
3737 {
3738 RtlCopyMemory(dst, src, w);
3739 src += ft_face->glyph->bitmap.pitch;
3740 dst += pitch;
3741 }
3742 break;
3743 }
3744
3745 case ft_glyph_format_outline:
3746 {
3747 ft_bitmap.width = width;
3748 ft_bitmap.rows = height;
3749 ft_bitmap.pitch = pitch;