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