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