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