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