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