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