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