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