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