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