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