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