[FONT][WIN32SS] Refactor the loop (4 of 5)
[reactos.git] / win32ss / gdi / ntgdi / freetype.c
1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/freetype.c
5 * PURPOSE: FreeType font engine interface
6 * PROGRAMMERS: Copyright 2001 Huw D M Davies for CodeWeavers.
7 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
8 * Copyright 2016-2018 Katayama Hirofumi MZ.
9 */
10
11 /** Includes ******************************************************************/
12
13 #include <win32k.h>
14
15 #include FT_GLYPH_H
16 #include FT_TYPE1_TABLES_H
17 #include FT_TRUETYPE_TABLES_H
18 #include FT_TRUETYPE_TAGS_H
19 #include FT_TRIGONOMETRY_H
20 #include FT_BITMAP_H
21 #include FT_OUTLINE_H
22 #include FT_WINFONTS_H
23 #include FT_SFNT_NAMES_H
24 #include FT_SYNTHESIS_H
25 #include FT_TRUETYPE_IDS_H
26
27 #ifndef FT_INTERNAL_INTERNAL_H
28 #define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h>
29 #include FT_INTERNAL_INTERNAL_H
30 #endif
31 #include FT_INTERNAL_TRUETYPE_TYPES_H
32
33 #include <gdi/eng/floatobj.h>
34 #include "font.h"
35
36 #define NDEBUG
37 #include <debug.h>
38
39 /* TPMF_FIXED_PITCH is confusing; brain-dead api */
40 #ifndef _TMPF_VARIABLE_PITCH
41 #define _TMPF_VARIABLE_PITCH TMPF_FIXED_PITCH
42 #endif
43
44 extern const MATRIX gmxWorldToDeviceDefault;
45 extern const MATRIX gmxWorldToPageDefault;
46
47 /* HACK!! Fix XFORMOBJ then use 1:16 / 16:1 */
48 #define gmxWorldToDeviceDefault gmxWorldToPageDefault
49
50 FT_Library g_FreeTypeLibrary;
51
52 /* special font names */
53 static const UNICODE_STRING g_MarlettW = RTL_CONSTANT_STRING(L"Marlett");
54
55 /* registry */
56 static UNICODE_STRING g_FontRegPath =
57 RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
58
59
60 /* The FreeType library is not thread safe, so we have
61 to serialize access to it */
62 static PFAST_MUTEX g_FreeTypeLock;
63
64 static LIST_ENTRY g_FontListHead;
65 static PFAST_MUTEX g_FontListLock;
66 static BOOL g_RenderingEnabled = TRUE;
67
68 #define IntLockGlobalFonts() \
69 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FontListLock)
70
71 #define IntUnLockGlobalFonts() \
72 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FontListLock)
73
74 #define ASSERT_GLOBALFONTS_LOCK_HELD() \
75 ASSERT(g_FontListLock->Owner == KeGetCurrentThread())
76
77 #define IntLockFreeType() \
78 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FreeTypeLock)
79
80 #define IntUnLockFreeType() \
81 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FreeTypeLock)
82
83 #define ASSERT_FREETYPE_LOCK_HELD() \
84 ASSERT(g_FreeTypeLock->Owner == KeGetCurrentThread())
85
86 #define ASSERT_FREETYPE_LOCK_NOT_HELD() \
87 ASSERT(g_FreeTypeLock->Owner != KeGetCurrentThread())
88
89 #define MAX_FONT_CACHE 256
90
91 static LIST_ENTRY g_FontCacheListHead;
92 static UINT g_FontCacheNumEntries;
93
94 static PWCHAR g_ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */
95 {
96 L"Western", /* 00 */
97 L"Central_European",
98 L"Cyrillic",
99 L"Greek",
100 L"Turkish",
101 L"Hebrew",
102 L"Arabic",
103 L"Baltic",
104 L"Vietnamese", /* 08 */
105 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */
106 L"Thai",
107 L"Japanese",
108 L"CHINESE_GB2312",
109 L"Hangul",
110 L"CHINESE_BIG5",
111 L"Hangul(Johab)",
112 NULL, NULL, /* 23 */
113 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
114 L"Symbol" /* 31 */
115 };
116
117 /*
118 * For TranslateCharsetInfo
119 */
120 #define CP_SYMBOL 42
121 #define MAXTCIINDEX 32
122 static const CHARSETINFO g_FontTci[MAXTCIINDEX] =
123 {
124 /* ANSI */
125 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
126 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
127 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
128 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
129 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
130 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
131 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
132 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
133 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
134 /* reserved by ANSI */
135 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
136 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
137 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
138 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
139 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
140 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
141 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
142 /* ANSI and OEM */
143 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
144 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
145 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
146 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
147 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
148 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
149 /* Reserved for alternate ANSI and OEM */
150 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
151 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
152 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
153 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
154 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
155 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
157 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
158 /* Reserved for system */
159 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
160 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
161 };
162
163 #ifndef CP_OEMCP
164 #define CP_OEMCP 1
165 #define CP_MACCP 2
166 #endif
167
168 /* Get charset from specified codepage.
169 g_FontTci is used also in TranslateCharsetInfo. */
170 BYTE FASTCALL IntCharSetFromCodePage(UINT uCodePage)
171 {
172 UINT i;
173
174 if (uCodePage == CP_OEMCP)
175 return OEM_CHARSET;
176
177 if (uCodePage == CP_MACCP)
178 return MAC_CHARSET;
179
180 for (i = 0; i < MAXTCIINDEX; ++i)
181 {
182 if (g_FontTci[i].ciACP == 0)
183 continue;
184
185 if (g_FontTci[i].ciACP == uCodePage)
186 return g_FontTci[i].ciCharset;
187 }
188
189 return DEFAULT_CHARSET;
190 }
191
192 /* list head */
193 static RTL_STATIC_LIST_HEAD(g_FontSubstListHead);
194
195 static void
196 SharedMem_AddRef(PSHARED_MEM Ptr)
197 {
198 ASSERT_FREETYPE_LOCK_HELD();
199
200 ++Ptr->RefCount;
201 }
202
203 static void
204 SharedFaceCache_Init(PSHARED_FACE_CACHE Cache)
205 {
206 Cache->OutlineRequiredSize = 0;
207 RtlInitUnicodeString(&Cache->FontFamily, NULL);
208 RtlInitUnicodeString(&Cache->FullName, NULL);
209 }
210
211 static PSHARED_FACE
212 SharedFace_Create(FT_Face Face, PSHARED_MEM Memory)
213 {
214 PSHARED_FACE Ptr;
215 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
216 if (Ptr)
217 {
218 Ptr->Face = Face;
219 Ptr->RefCount = 1;
220 Ptr->Memory = Memory;
221 SharedFaceCache_Init(&Ptr->EnglishUS);
222 SharedFaceCache_Init(&Ptr->UserLanguage);
223
224 SharedMem_AddRef(Memory);
225 DPRINT("Creating SharedFace for %s\n", Face->family_name ? Face->family_name : "<NULL>");
226 }
227 return Ptr;
228 }
229
230 static PSHARED_MEM
231 SharedMem_Create(PBYTE Buffer, ULONG BufferSize, BOOL IsMapping)
232 {
233 PSHARED_MEM Ptr;
234 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_MEM), TAG_FONT);
235 if (Ptr)
236 {
237 Ptr->Buffer = Buffer;
238 Ptr->BufferSize = BufferSize;
239 Ptr->RefCount = 1;
240 Ptr->IsMapping = IsMapping;
241 DPRINT("Creating SharedMem for %p (%i, %p)\n", Buffer, IsMapping, Ptr);
242 }
243 return Ptr;
244 }
245
246 static void
247 SharedFace_AddRef(PSHARED_FACE Ptr)
248 {
249 ASSERT_FREETYPE_LOCK_HELD();
250
251 ++Ptr->RefCount;
252 }
253
254 static void
255 RemoveCachedEntry(PFONT_CACHE_ENTRY Entry)
256 {
257 ASSERT_FREETYPE_LOCK_HELD();
258
259 FT_Done_Glyph((FT_Glyph)Entry->BitmapGlyph);
260 RemoveEntryList(&Entry->ListEntry);
261 ExFreePoolWithTag(Entry, TAG_FONT);
262 g_FontCacheNumEntries--;
263 ASSERT(g_FontCacheNumEntries <= MAX_FONT_CACHE);
264 }
265
266 static void
267 RemoveCacheEntries(FT_Face Face)
268 {
269 PLIST_ENTRY CurrentEntry;
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 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
1995 {
1996 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1997
1998 FontGDI = CurrentEntry->Font;
1999 ASSERT(FontGDI);
2000
2001 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
2002 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2003 if (!NT_SUCCESS(status))
2004 {
2005 break;
2006 }
2007
2008 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2009 {
2010 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2011 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2012 }
2013
2014 if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE))
2015 {
2016 RtlFreeUnicodeString(&EntryFaceNameW);
2017 return FontGDI;
2018 }
2019
2020 RtlFreeUnicodeString(&EntryFaceNameW);
2021 }
2022
2023 return NULL;
2024 }
2025
2026 static PFONTGDI FASTCALL
2027 FindFaceNameInLists(PUNICODE_STRING FaceName)
2028 {
2029 PPROCESSINFO Win32Process;
2030 PFONTGDI Font;
2031
2032 /* Search the process local list.
2033 We do not have to search the 'Mem' list, since those fonts are linked in the PrivateFontListHead */
2034 Win32Process = PsGetCurrentProcessWin32Process();
2035 IntLockProcessPrivateFonts(Win32Process);
2036 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
2037 IntUnLockProcessPrivateFonts(Win32Process);
2038 if (NULL != Font)
2039 {
2040 return Font;
2041 }
2042
2043 /* Search the global list */
2044 IntLockGlobalFonts();
2045 Font = FindFaceNameInList(FaceName, &g_FontListHead);
2046 IntUnLockGlobalFonts();
2047
2048 return Font;
2049 }
2050
2051 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
2052 static BYTE
2053 CharSetFromLangID(LANGID LangID)
2054 {
2055 /* FIXME: Add more and fix if wrong */
2056 switch (PRIMARYLANGID(LangID))
2057 {
2058 case LANG_CHINESE:
2059 switch (SUBLANGID(LangID))
2060 {
2061 case SUBLANG_CHINESE_TRADITIONAL:
2062 return CHINESEBIG5_CHARSET;
2063 case SUBLANG_CHINESE_SIMPLIFIED:
2064 default:
2065 break;
2066 }
2067 return GB2312_CHARSET;
2068
2069 case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
2070 case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
2071 return EASTEUROPE_CHARSET;
2072
2073 case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
2074 case LANG_SERBIAN: case LANG_UKRAINIAN:
2075 return RUSSIAN_CHARSET;
2076
2077 case LANG_ARABIC: return ARABIC_CHARSET;
2078 case LANG_GREEK: return GREEK_CHARSET;
2079 case LANG_HEBREW: return HEBREW_CHARSET;
2080 case LANG_JAPANESE: return SHIFTJIS_CHARSET;
2081 case LANG_KOREAN: return JOHAB_CHARSET;
2082 case LANG_TURKISH: return TURKISH_CHARSET;
2083 case LANG_THAI: return THAI_CHARSET;
2084 case LANG_LATVIAN: return BALTIC_CHARSET;
2085 case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
2086
2087 case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
2088 case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
2089 case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
2090 case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
2091 case LANG_SWEDISH: default:
2092 return ANSI_CHARSET;
2093 }
2094 }
2095
2096 static void
2097 SwapEndian(LPVOID pvData, DWORD Size)
2098 {
2099 BYTE b, *pb = pvData;
2100 Size /= 2;
2101 while (Size-- > 0)
2102 {
2103 b = pb[0];
2104 pb[0] = pb[1];
2105 pb[1] = b;
2106 ++pb; ++pb;
2107 }
2108 }
2109
2110 static NTSTATUS
2111 DuplicateUnicodeString(PUNICODE_STRING Source, PUNICODE_STRING Destination)
2112 {
2113 NTSTATUS Status = STATUS_NO_MEMORY;
2114 UNICODE_STRING Tmp;
2115
2116 Tmp.Buffer = ExAllocatePoolWithTag(PagedPool, Source->MaximumLength, TAG_USTR);
2117 if (Tmp.Buffer)
2118 {
2119 Tmp.MaximumLength = Source->MaximumLength;
2120 Tmp.Length = 0;
2121 RtlCopyUnicodeString(&Tmp, Source);
2122
2123 Destination->MaximumLength = Tmp.MaximumLength;
2124 Destination->Length = Tmp.Length;
2125 Destination->Buffer = Tmp.Buffer;
2126
2127 Status = STATUS_SUCCESS;
2128 }
2129
2130 return Status;
2131 }
2132
2133 static NTSTATUS
2134 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
2135 FT_UShort NameID, FT_UShort LangID)
2136 {
2137 FT_SfntName Name;
2138 INT i, Count, BestIndex, Score, BestScore;
2139 FT_Error Error;
2140 NTSTATUS Status = STATUS_NOT_FOUND;
2141 ANSI_STRING AnsiName;
2142 PSHARED_FACE_CACHE Cache;
2143 FT_Face Face = SharedFace->Face;
2144
2145 RtlFreeUnicodeString(pNameW);
2146
2147 /* select cache */
2148 if (PRIMARYLANGID(LangID) == LANG_ENGLISH)
2149 {
2150 Cache = &SharedFace->EnglishUS;
2151 }
2152 else
2153 {
2154 Cache = &SharedFace->UserLanguage;
2155 }
2156
2157 /* use cache if available */
2158 if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer)
2159 {
2160 return DuplicateUnicodeString(&Cache->FontFamily, pNameW);
2161 }
2162 if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer)
2163 {
2164 return DuplicateUnicodeString(&Cache->FullName, pNameW);
2165 }
2166
2167 BestIndex = -1;
2168 BestScore = 0;
2169
2170 Count = FT_Get_Sfnt_Name_Count(Face);
2171 for (i = 0; i < Count; ++i)
2172 {
2173 Error = FT_Get_Sfnt_Name(Face, i, &Name);
2174 if (Error)
2175 {
2176 continue; /* failure */
2177 }
2178
2179 if (Name.name_id != NameID)
2180 {
2181 continue; /* mismatched */
2182 }
2183
2184 if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
2185 (Name.encoding_id != TT_MS_ID_UNICODE_CS &&
2186 Name.encoding_id != TT_MS_ID_SYMBOL_CS))
2187 {
2188 continue; /* not Microsoft Unicode name */
2189 }
2190
2191 if (Name.string == NULL || Name.string_len == 0 ||
2192 (Name.string[0] == 0 && Name.string[1] == 0))
2193 {
2194 continue; /* invalid string */
2195 }
2196
2197 if (Name.language_id == LangID)
2198 {
2199 Score = 30;
2200 BestIndex = i;
2201 break; /* best match */
2202 }
2203 else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID))
2204 {
2205 Score = 20;
2206 }
2207 else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH)
2208 {
2209 Score = 10;
2210 }
2211 else
2212 {
2213 Score = 0;
2214 }
2215
2216 if (Score > BestScore)
2217 {
2218 BestScore = Score;
2219 BestIndex = i;
2220 }
2221 }
2222
2223 if (BestIndex >= 0)
2224 {
2225 /* store the best name */
2226 Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
2227 if (!Error)
2228 {
2229 /* NOTE: Name.string is not null-terminated */
2230 UNICODE_STRING Tmp;
2231 Tmp.Buffer = (PWCH)Name.string;
2232 Tmp.Length = Tmp.MaximumLength = Name.string_len;
2233
2234 pNameW->Length = 0;
2235 pNameW->MaximumLength = Name.string_len + sizeof(WCHAR);
2236 pNameW->Buffer = ExAllocatePoolWithTag(PagedPool, pNameW->MaximumLength, TAG_USTR);
2237
2238 if (pNameW->Buffer)
2239 {
2240 Status = RtlAppendUnicodeStringToString(pNameW, &Tmp);
2241 if (Status == STATUS_SUCCESS)
2242 {
2243 /* Convert UTF-16 big endian to little endian */
2244 SwapEndian(pNameW->Buffer, pNameW->Length);
2245 }
2246 }
2247 else
2248 {
2249 Status = STATUS_INSUFFICIENT_RESOURCES;
2250 }
2251 }
2252 }
2253
2254 if (!NT_SUCCESS(Status))
2255 {
2256 /* defaulted */
2257 if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
2258 {
2259 RtlInitAnsiString(&AnsiName, Face->style_name);
2260 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2261 }
2262 else
2263 {
2264 RtlInitAnsiString(&AnsiName, Face->family_name);
2265 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2266 }
2267 }
2268
2269 if (NT_SUCCESS(Status))
2270 {
2271 /* make cache */
2272 if (NameID == TT_NAME_ID_FONT_FAMILY)
2273 {
2274 ASSERT_FREETYPE_LOCK_NOT_HELD();
2275 IntLockFreeType();
2276 if (!Cache->FontFamily.Buffer)
2277 DuplicateUnicodeString(pNameW, &Cache->FontFamily);
2278 IntUnLockFreeType();
2279 }
2280 else if (NameID == TT_NAME_ID_FULL_NAME)
2281 {
2282 ASSERT_FREETYPE_LOCK_NOT_HELD();
2283 IntLockFreeType();
2284 if (!Cache->FullName.Buffer)
2285 DuplicateUnicodeString(pNameW, &Cache->FullName);
2286 IntUnLockFreeType();
2287 }
2288 }
2289
2290 return Status;
2291 }
2292
2293 static void FASTCALL
2294 FontFamilyFillInfo(PFONTFAMILYINFO Info, LPCWSTR FaceName,
2295 LPCWSTR FullName, PFONTGDI FontGDI)
2296 {
2297 ANSI_STRING StyleA;
2298 UNICODE_STRING StyleW;
2299 TT_OS2 *pOS2;
2300 FONTSIGNATURE fs;
2301 CHARSETINFO CharSetInfo;
2302 unsigned i, Size;
2303 OUTLINETEXTMETRICW *Otm;
2304 LOGFONTW *Lf;
2305 TEXTMETRICW *TM;
2306 NEWTEXTMETRICW *Ntm;
2307 DWORD fs0;
2308 NTSTATUS status;
2309 PSHARED_FACE SharedFace = FontGDI->SharedFace;
2310 FT_Face Face = SharedFace->Face;
2311 UNICODE_STRING NameW;
2312
2313 RtlInitUnicodeString(&NameW, NULL);
2314 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
2315 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2316 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2317 if (!Otm)
2318 {
2319 return;
2320 }
2321 Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2322 if (!Size)
2323 {
2324 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2325 return;
2326 }
2327
2328 Lf = &Info->EnumLogFontEx.elfLogFont;
2329 TM = &Otm->otmTextMetrics;
2330
2331 Lf->lfHeight = TM->tmHeight;
2332 Lf->lfWidth = TM->tmAveCharWidth;
2333 Lf->lfWeight = TM->tmWeight;
2334 Lf->lfItalic = TM->tmItalic;
2335 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
2336 Lf->lfCharSet = TM->tmCharSet;
2337 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
2338 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
2339 Lf->lfQuality = PROOF_QUALITY;
2340
2341 Ntm = &Info->NewTextMetricEx.ntmTm;
2342 Ntm->tmHeight = TM->tmHeight;
2343 Ntm->tmAscent = TM->tmAscent;
2344 Ntm->tmDescent = TM->tmDescent;
2345 Ntm->tmInternalLeading = TM->tmInternalLeading;
2346 Ntm->tmExternalLeading = TM->tmExternalLeading;
2347 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
2348 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
2349 Ntm->tmWeight = TM->tmWeight;
2350 Ntm->tmOverhang = TM->tmOverhang;
2351 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
2352 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
2353 Ntm->tmFirstChar = TM->tmFirstChar;
2354 Ntm->tmLastChar = TM->tmLastChar;
2355 Ntm->tmDefaultChar = TM->tmDefaultChar;
2356 Ntm->tmBreakChar = TM->tmBreakChar;
2357 Ntm->tmItalic = TM->tmItalic;
2358 Ntm->tmUnderlined = TM->tmUnderlined;
2359 Ntm->tmStruckOut = TM->tmStruckOut;
2360 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
2361 Ntm->tmCharSet = TM->tmCharSet;
2362 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
2363
2364 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
2365
2366 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
2367
2368 Ntm->ntmSizeEM = Otm->otmEMSquare;
2369 Ntm->ntmCellHeight = Otm->otmEMSquare;
2370 Ntm->ntmAvgWidth = 0;
2371
2372 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
2373 ? TRUETYPE_FONTTYPE : 0);
2374
2375 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
2376 Info->FontType |= RASTER_FONTTYPE;
2377
2378
2379 /* face name */
2380 if (!FaceName)
2381 FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
2382
2383 RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
2384
2385 /* full name */
2386 if (!FullName)
2387 FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName);
2388
2389 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2390 sizeof(Info->EnumLogFontEx.elfFullName),
2391 FullName);
2392
2393 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2394
2395 RtlInitAnsiString(&StyleA, Face->style_name);
2396 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
2397 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
2398 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
2399 if (!NT_SUCCESS(status))
2400 {
2401 return;
2402 }
2403 Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
2404
2405 IntLockFreeType();
2406 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2407
2408 if (!pOS2)
2409 {
2410 IntUnLockFreeType();
2411 return;
2412 }
2413
2414 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2415 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2416 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2417 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2418 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2419 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2420
2421 if (0 == pOS2->version)
2422 {
2423 FT_UInt Dummy;
2424
2425 if (FT_Get_First_Char(Face, &Dummy) < 0x100)
2426 fs.fsCsb[0] |= FS_LATIN1;
2427 else
2428 fs.fsCsb[0] |= FS_SYMBOL;
2429 }
2430 IntUnLockFreeType();
2431
2432 if (fs.fsCsb[0] == 0)
2433 {
2434 /* Let's see if we can find any interesting cmaps */
2435 for (i = 0; i < (UINT)Face->num_charmaps; i++)
2436 {
2437 switch (Face->charmaps[i]->encoding)
2438 {
2439 case FT_ENCODING_UNICODE:
2440 case FT_ENCODING_APPLE_ROMAN:
2441 fs.fsCsb[0] |= FS_LATIN1;
2442 break;
2443 case FT_ENCODING_MS_SYMBOL:
2444 fs.fsCsb[0] |= FS_SYMBOL;
2445 break;
2446 default:
2447 break;
2448 }
2449 }
2450 }
2451
2452 for (i = 0; i < MAXTCIINDEX; i++)
2453 {
2454 fs0 = 1L << i;
2455 if (fs.fsCsb[0] & fs0)
2456 {
2457 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
2458 {
2459 CharSetInfo.ciCharset = DEFAULT_CHARSET;
2460 }
2461 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
2462 {
2463 if (g_ElfScripts[i])
2464 wcscpy(Info->EnumLogFontEx.elfScript, g_ElfScripts[i]);
2465 else
2466 {
2467 DPRINT1("Unknown elfscript for bit %u\n", i);
2468 }
2469 }
2470 }
2471 }
2472 Info->NewTextMetricEx.ntmFontSig = fs;
2473 }
2474
2475 static int FASTCALL
2476 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
2477 {
2478 DWORD i;
2479 UNICODE_STRING InfoFaceName;
2480
2481 for (i = 0; i < InfoEntries; i++)
2482 {
2483 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
2484 if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE))
2485 {
2486 return i;
2487 }
2488 }
2489
2490 return -1;
2491 }
2492
2493 static BOOLEAN FASTCALL
2494 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
2495 PFONTFAMILYINFO Info, DWORD InfoEntries)
2496 {
2497 UNICODE_STRING LogFontFaceName;
2498
2499 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
2500 if (0 != LogFontFaceName.Length &&
2501 !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE))
2502 {
2503 return FALSE;
2504 }
2505
2506 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
2507 }
2508
2509 static BOOL FASTCALL
2510 FontFamilyFound(PFONTFAMILYINFO InfoEntry,
2511 PFONTFAMILYINFO Info, DWORD InfoCount)
2512 {
2513 LPLOGFONTW plf1 = &InfoEntry->EnumLogFontEx.elfLogFont;
2514 LPWSTR pFullName1 = InfoEntry->EnumLogFontEx.elfFullName;
2515 LPWSTR pFullName2;
2516 DWORD i;
2517
2518 for (i = 0; i < InfoCount; ++i)
2519 {
2520 LPLOGFONTW plf2 = &Info[i].EnumLogFontEx.elfLogFont;
2521 if (plf1->lfCharSet != plf2->lfCharSet)
2522 continue;
2523
2524 pFullName2 = Info[i].EnumLogFontEx.elfFullName;
2525 if (_wcsicmp(pFullName1, pFullName2) != 0)
2526 continue;
2527
2528 return TRUE;
2529 }
2530 return FALSE;
2531 }
2532
2533 static BOOLEAN FASTCALL
2534 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
2535 PFONTFAMILYINFO Info,
2536 DWORD *pCount,
2537 DWORD MaxCount,
2538 PLIST_ENTRY Head)
2539 {
2540 PLIST_ENTRY Entry;
2541 PFONT_ENTRY CurrentEntry;
2542 FONTGDI *FontGDI;
2543 FONTFAMILYINFO InfoEntry;
2544 DWORD Count = *pCount;
2545
2546 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
2547 {
2548 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2549 FontGDI = CurrentEntry->Font;
2550 ASSERT(FontGDI);
2551
2552 if (LogFont->lfCharSet != DEFAULT_CHARSET &&
2553 LogFont->lfCharSet != FontGDI->CharSet)
2554 {
2555 continue;
2556 }
2557
2558 if (LogFont->lfFaceName[0] == UNICODE_NULL)
2559 {
2560 if (Count < MaxCount)
2561 {
2562 FontFamilyFillInfo(&Info[Count], NULL, NULL, FontGDI);
2563 }
2564 Count++;
2565 continue;
2566 }
2567
2568 FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
2569
2570 if (_wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0 &&
2571 _wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfFullName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0)
2572 {
2573 continue;
2574 }
2575
2576 if (!FontFamilyFound(&InfoEntry, Info, min(Count, MaxCount)))
2577 {
2578 if (Count < MaxCount)
2579 {
2580 RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
2581 }
2582 Count++;
2583 }
2584 }
2585
2586 *pCount = Count;
2587
2588 return TRUE;
2589 }
2590
2591 static BOOLEAN FASTCALL
2592 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
2593 PFONTFAMILYINFO Info,
2594 DWORD *pCount,
2595 DWORD MaxCount)
2596 {
2597 PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead;
2598 PFONTSUBST_ENTRY pCurrentEntry;
2599 PUNICODE_STRING pFromW;
2600 FONTGDI *FontGDI;
2601 LOGFONTW lf = *LogFont;
2602 UNICODE_STRING NameW;
2603
2604 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
2605 {
2606 pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
2607
2608 pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
2609 if (LogFont->lfFaceName[0] != UNICODE_NULL)
2610 {
2611 if (!FontFamilyInclude(LogFont, pFromW, Info, min(*pCount, MaxCount)))
2612 continue; /* mismatch */
2613 }
2614
2615 RtlStringCchCopyW(lf.lfFaceName, LF_FACESIZE, pFromW->Buffer);
2616 SubstituteFontRecurse(&lf);
2617
2618 RtlInitUnicodeString(&NameW, lf.lfFaceName);
2619 FontGDI = FindFaceNameInLists(&NameW);
2620 if (FontGDI == NULL)
2621 {
2622 continue; /* no real font */
2623 }
2624
2625 if (*pCount < MaxCount)
2626 {
2627 FontFamilyFillInfo(&Info[*pCount], pFromW->Buffer, NULL, FontGDI);
2628 }
2629 (*pCount)++;
2630 }
2631
2632 return TRUE;
2633 }
2634
2635 BOOL
2636 FASTCALL
2637 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
2638 {
2639 if ( lprs )
2640 {
2641 lprs->nSize = sizeof(RASTERIZER_STATUS);
2642 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
2643 lprs->nLanguageID = gusLanguageID;
2644 return TRUE;
2645 }
2646 EngSetLastError(ERROR_INVALID_PARAMETER);
2647 return FALSE;
2648 }
2649
2650 static
2651 BOOL
2652 SameScaleMatrix(
2653 PMATRIX pmx1,
2654 PMATRIX pmx2)
2655 {
2656 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
2657 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
2658 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
2659 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
2660 }
2661
2662 FT_BitmapGlyph APIENTRY
2663 ftGdiGlyphCacheGet(
2664 FT_Face Face,
2665 INT GlyphIndex,
2666 INT Height,
2667 FT_Render_Mode RenderMode,
2668 PMATRIX pmx)
2669 {
2670 PLIST_ENTRY CurrentEntry;
2671 PFONT_CACHE_ENTRY FontEntry;
2672
2673 ASSERT_FREETYPE_LOCK_HELD();
2674
2675 for (CurrentEntry = g_FontCacheListHead.Flink;
2676 CurrentEntry != &g_FontCacheListHead;
2677 CurrentEntry = CurrentEntry->Flink)
2678 {
2679 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
2680 if ((FontEntry->Face == Face) &&
2681 (FontEntry->GlyphIndex == GlyphIndex) &&
2682 (FontEntry->Height == Height) &&
2683 (FontEntry->RenderMode == RenderMode) &&
2684 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2685 break;
2686 }
2687
2688 if (CurrentEntry == &g_FontCacheListHead)
2689 {
2690 return NULL;
2691 }
2692
2693 RemoveEntryList(CurrentEntry);
2694 InsertHeadList(&g_FontCacheListHead, CurrentEntry);
2695 return FontEntry->BitmapGlyph;
2696 }
2697
2698 /* no cache */
2699 FT_BitmapGlyph APIENTRY
2700 ftGdiGlyphSet(
2701 FT_Face Face,
2702 FT_GlyphSlot GlyphSlot,
2703 FT_Render_Mode RenderMode)
2704 {
2705 FT_Glyph Glyph;
2706 INT error;
2707 FT_Bitmap AlignedBitmap;
2708 FT_BitmapGlyph BitmapGlyph;
2709
2710 error = FT_Get_Glyph(GlyphSlot, &Glyph);
2711 if (error)
2712 {
2713 DPRINT1("Failure getting glyph.\n");
2714 return NULL;
2715 }
2716
2717 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2718 if (error)
2719 {
2720 FT_Done_Glyph(Glyph);
2721 DPRINT1("Failure rendering glyph.\n");
2722 return NULL;
2723 }
2724
2725 BitmapGlyph = (FT_BitmapGlyph)Glyph;
2726 FT_Bitmap_New(&AlignedBitmap);
2727 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2728 {
2729 DPRINT1("Conversion failed\n");
2730 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2731 return NULL;
2732 }
2733
2734 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2735 BitmapGlyph->bitmap = AlignedBitmap;
2736
2737 return BitmapGlyph;
2738 }
2739
2740 FT_BitmapGlyph APIENTRY
2741 ftGdiGlyphCacheSet(
2742 FT_Face Face,
2743 INT GlyphIndex,
2744 INT Height,
2745 PMATRIX pmx,
2746 FT_GlyphSlot GlyphSlot,
2747 FT_Render_Mode RenderMode)
2748 {
2749 FT_Glyph GlyphCopy;
2750 INT error;
2751 PFONT_CACHE_ENTRY NewEntry;
2752 FT_Bitmap AlignedBitmap;
2753 FT_BitmapGlyph BitmapGlyph;
2754
2755 ASSERT_FREETYPE_LOCK_HELD();
2756
2757 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2758 if (error)
2759 {
2760 DPRINT1("Failure caching glyph.\n");
2761 return NULL;
2762 };
2763
2764 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2765 if (error)
2766 {
2767 FT_Done_Glyph(GlyphCopy);
2768 DPRINT1("Failure rendering glyph.\n");
2769 return NULL;
2770 };
2771
2772 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
2773 if (!NewEntry)
2774 {
2775 DPRINT1("Alloc failure caching glyph.\n");
2776 FT_Done_Glyph(GlyphCopy);
2777 return NULL;
2778 }
2779
2780 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2781 FT_Bitmap_New(&AlignedBitmap);
2782 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2783 {
2784 DPRINT1("Conversion failed\n");
2785 ExFreePoolWithTag(NewEntry, TAG_FONT);
2786 FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
2787 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2788 return NULL;
2789 }
2790
2791 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2792 BitmapGlyph->bitmap = AlignedBitmap;
2793
2794 NewEntry->GlyphIndex = GlyphIndex;
2795 NewEntry->Face = Face;
2796 NewEntry->BitmapGlyph = BitmapGlyph;
2797 NewEntry->Height = Height;
2798 NewEntry->RenderMode = RenderMode;
2799 NewEntry->mxWorldToDevice = *pmx;
2800
2801 InsertHeadList(&g_FontCacheListHead, &NewEntry->ListEntry);
2802 if (++g_FontCacheNumEntries > MAX_FONT_CACHE)
2803 {
2804 NewEntry = CONTAINING_RECORD(g_FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
2805 RemoveCachedEntry(NewEntry);
2806 }
2807
2808 return BitmapGlyph;
2809 }
2810
2811
2812 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2813 {
2814 pt->x.value = vec->x >> 6;
2815 pt->x.fract = (vec->x & 0x3f) << 10;
2816 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2817 pt->y.value = vec->y >> 6;
2818 pt->y.fract = (vec->y & 0x3f) << 10;
2819 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2820 }
2821
2822 /*
2823 This function builds an FT_Fixed from a float. It puts the integer part
2824 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2825 It fails if the integer part of the float number is greater than SHORT_MAX.
2826 */
2827 static __inline FT_Fixed FT_FixedFromFloat(float f)
2828 {
2829 short value = f;
2830 unsigned short fract = (f - value) * 0xFFFF;
2831 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2832 }
2833
2834 /*
2835 This function builds an FT_Fixed from a FIXED. It simply put f.value
2836 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2837 */
2838 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2839 {
2840 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2841 }
2842
2843 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2844 {
2845 TTPOLYGONHEADER *pph;
2846 TTPOLYCURVE *ppc;
2847 int needed = 0, point = 0, contour, first_pt;
2848 unsigned int pph_start, cpfx;
2849 DWORD type;
2850
2851 for (contour = 0; contour < outline->n_contours; contour++)
2852 {
2853 /* Ignore contours containing one point */
2854 if (point == outline->contours[contour])
2855 {
2856 point++;
2857 continue;
2858 }
2859
2860 pph_start = needed;
2861 pph = (TTPOLYGONHEADER *)(buf + needed);
2862 first_pt = point;
2863 if (buf)
2864 {
2865 pph->dwType = TT_POLYGON_TYPE;
2866 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2867 }
2868 needed += sizeof(*pph);
2869 point++;
2870 while (point <= outline->contours[contour])
2871 {
2872 ppc = (TTPOLYCURVE *)(buf + needed);
2873 type = outline->tags[point] & FT_Curve_Tag_On ?
2874 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2875 cpfx = 0;
2876 do
2877 {
2878 if (buf)
2879 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2880 cpfx++;
2881 point++;
2882 } while (point <= outline->contours[contour] &&
2883 (outline->tags[point] & FT_Curve_Tag_On) ==
2884 (outline->tags[point-1] & FT_Curve_Tag_On));
2885 /* At the end of a contour Windows adds the start point, but
2886 only for Beziers */
2887 if (point > outline->contours[contour] &&
2888 !(outline->tags[point-1] & FT_Curve_Tag_On))
2889 {
2890 if (buf)
2891 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2892 cpfx++;
2893 }
2894 else if (point <= outline->contours[contour] &&
2895 outline->tags[point] & FT_Curve_Tag_On)
2896 {
2897 /* add closing pt for bezier */
2898 if (buf)
2899 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2900 cpfx++;
2901 point++;
2902 }
2903 if (buf)
2904 {
2905 ppc->wType = type;
2906 ppc->cpfx = cpfx;
2907 }
2908 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2909 }
2910 if (buf)
2911 pph->cb = needed - pph_start;
2912 }
2913 return needed;
2914 }
2915
2916 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2917 {
2918 /* Convert the quadratic Beziers to cubic Beziers.
2919 The parametric eqn for a cubic Bezier is, from PLRM:
2920 r(t) = at^3 + bt^2 + ct + r0
2921 with the control points:
2922 r1 = r0 + c/3
2923 r2 = r1 + (c + b)/3
2924 r3 = r0 + c + b + a
2925
2926 A quadratic Bezier has the form:
2927 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2928
2929 So equating powers of t leads to:
2930 r1 = 2/3 p1 + 1/3 p0
2931 r2 = 2/3 p1 + 1/3 p2
2932 and of course r0 = p0, r3 = p2
2933 */
2934 int contour, point = 0, first_pt;
2935 TTPOLYGONHEADER *pph;
2936 TTPOLYCURVE *ppc;
2937 DWORD pph_start, cpfx, type;
2938 FT_Vector cubic_control[4];
2939 unsigned int needed = 0;
2940
2941 for (contour = 0; contour < outline->n_contours; contour++)
2942 {
2943 pph_start = needed;
2944 pph = (TTPOLYGONHEADER *)(buf + needed);
2945 first_pt = point;
2946 if (buf)
2947 {
2948 pph->dwType = TT_POLYGON_TYPE;
2949 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2950 }
2951 needed += sizeof(*pph);
2952 point++;
2953 while (point <= outline->contours[contour])
2954 {
2955 ppc = (TTPOLYCURVE *)(buf + needed);
2956 type = outline->tags[point] & FT_Curve_Tag_On ?
2957 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2958 cpfx = 0;
2959 do
2960 {
2961 if (type == TT_PRIM_LINE)
2962 {
2963 if (buf)
2964 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2965 cpfx++;
2966 point++;
2967 }
2968 else
2969 {
2970 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2971 so cpfx = 3n */
2972
2973 /* FIXME: Possible optimization in endpoint calculation
2974 if there are two consecutive curves */
2975 cubic_control[0] = outline->points[point-1];
2976 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2977 {
2978 cubic_control[0].x += outline->points[point].x + 1;
2979 cubic_control[0].y += outline->points[point].y + 1;
2980 cubic_control[0].x >>= 1;
2981 cubic_control[0].y >>= 1;
2982 }
2983 if (point+1 > outline->contours[contour])
2984 cubic_control[3] = outline->points[first_pt];
2985 else
2986 {
2987 cubic_control[3] = outline->points[point+1];
2988 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2989 {
2990 cubic_control[3].x += outline->points[point].x + 1;
2991 cubic_control[3].y += outline->points[point].y + 1;
2992 cubic_control[3].x >>= 1;
2993 cubic_control[3].y >>= 1;
2994 }
2995 }
2996 /* r1 = 1/3 p0 + 2/3 p1
2997 r2 = 1/3 p2 + 2/3 p1 */
2998 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2999 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3000 cubic_control[2] = cubic_control[1];
3001 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3002 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3003 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3004 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3005 if (buf)
3006 {
3007 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3008 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3009 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3010 }
3011 cpfx += 3;
3012 point++;
3013 }
3014 } while (point <= outline->contours[contour] &&
3015 (outline->tags[point] & FT_Curve_Tag_On) ==
3016 (outline->tags[point-1] & FT_Curve_Tag_On));
3017 /* At the end of a contour Windows adds the start point,
3018 but only for Beziers and we've already done that.
3019 */
3020 if (point <= outline->contours[contour] &&
3021 outline->tags[point] & FT_Curve_Tag_On)
3022 {
3023 /* This is the closing pt of a bezier, but we've already
3024 added it, so just inc point and carry on */
3025 point++;
3026 }
3027 if (buf)
3028 {
3029 ppc->wType = type;
3030 ppc->cpfx = cpfx;
3031 }
3032 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3033 }
3034 if (buf)
3035 pph->cb = needed - pph_start;
3036 }
3037 return needed;
3038 }
3039
3040 static FT_Error
3041 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
3042 {
3043 FT_Error error;
3044 FT_Size_RequestRec req;
3045 FT_Face face = FontGDI->SharedFace->Face;
3046 TT_OS2 *pOS2;
3047 TT_HoriHeader *pHori;
3048 FT_WinFNT_HeaderRec WinFNT;
3049 LONG Ascent, Descent, Sum, EmHeight64;
3050
3051 lfWidth = abs(lfWidth);
3052 if (lfHeight == 0)
3053 {
3054 if (lfWidth == 0)
3055 {
3056 DPRINT("lfHeight and lfWidth are zero.\n");
3057 lfHeight = -16;
3058 }
3059 else
3060 {
3061 lfHeight = lfWidth;
3062 }
3063 }
3064
3065 if (lfHeight == -1)
3066 lfHeight = -2;
3067
3068 ASSERT_FREETYPE_LOCK_HELD();
3069 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
3070 pHori = (TT_HoriHeader *)FT_Get_Sfnt_Table(face, FT_SFNT_HHEA);
3071
3072 if (!pOS2 || !pHori)
3073 {
3074 error = FT_Get_WinFNT_Header(face, &WinFNT);
3075 if (error)
3076 return error;
3077
3078 FontGDI->tmHeight = WinFNT.pixel_height;
3079 FontGDI->tmAscent = WinFNT.ascent;
3080 FontGDI->tmDescent = FontGDI->tmHeight - FontGDI->tmAscent;
3081 FontGDI->tmInternalLeading = WinFNT.internal_leading;
3082 FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3083 FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3084 FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3085 FontGDI->Magic = FONTGDI_MAGIC;
3086
3087 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
3088 req.width = 0;
3089 req.height = (FT_Long)(FontGDI->EmHeight << 6);
3090 req.horiResolution = 0;
3091 req.vertResolution = 0;
3092 return FT_Request_Size(face, &req);
3093 }
3094
3095 if (lfHeight > 0)
3096 {
3097 /* case (A): lfHeight is positive */
3098 Sum = pOS2->usWinAscent + pOS2->usWinDescent;
3099 if (Sum == 0)
3100 {
3101 Ascent = pHori->Ascender;
3102 Descent = -pHori->Descender;
3103 Sum = Ascent + Descent;
3104 }
3105 else
3106 {
3107 Ascent = pOS2->usWinAscent;
3108 Descent = pOS2->usWinDescent;
3109 }
3110
3111 FontGDI->tmAscent = FT_MulDiv(lfHeight, Ascent, Sum);
3112 FontGDI->tmDescent = FT_MulDiv(lfHeight, Descent, Sum);
3113 FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3114 FontGDI->tmInternalLeading = FontGDI->tmHeight - FT_MulDiv(lfHeight, face->units_per_EM, Sum);
3115 }
3116 else if (lfHeight < 0)
3117 {
3118 /* case (B): lfHeight is negative */
3119 FontGDI->tmAscent = FT_MulDiv(-lfHeight, pOS2->usWinAscent, face->units_per_EM);
3120 FontGDI->tmDescent = FT_MulDiv(-lfHeight, pOS2->usWinDescent, face->units_per_EM);
3121 FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3122 FontGDI->tmInternalLeading = FontGDI->tmHeight + lfHeight;
3123 }
3124
3125 FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3126 FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3127 FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3128 FontGDI->Magic = FONTGDI_MAGIC;
3129
3130 if (lfHeight > 0)
3131 EmHeight64 = (FontGDI->EmHeight << 6) + 31;
3132 else
3133 EmHeight64 = (FontGDI->EmHeight << 6);
3134
3135 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
3136 req.width = 0;
3137 req.height = EmHeight64;
3138 req.horiResolution = 0;
3139 req.vertResolution = 0;
3140 return FT_Request_Size(face, &req);
3141 }
3142
3143 BOOL
3144 FASTCALL
3145 TextIntUpdateSize(PDC dc,
3146 PTEXTOBJ TextObj,
3147 PFONTGDI FontGDI,
3148 BOOL bDoLock)
3149 {
3150 FT_Face face;
3151 INT error, n;
3152 FT_CharMap charmap, found;
3153 LOGFONTW *plf;
3154
3155 if (bDoLock)
3156 IntLockFreeType();
3157
3158 face = FontGDI->SharedFace->Face;
3159 if (face->charmap == NULL)
3160 {
3161 DPRINT("WARNING: No charmap selected!\n");
3162 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3163
3164 found = NULL;
3165 for (n = 0; n < face->num_charmaps; n++)
3166 {
3167 charmap = face->charmaps[n];
3168 if (charmap->encoding == FT_ENCODING_UNICODE)
3169 {
3170 found = charmap;
3171 break;
3172 }
3173 }
3174 if (!found)
3175 {
3176 for (n = 0; n < face->num_charmaps; n++)
3177 {
3178 charmap = face->charmaps[n];
3179 if (charmap->encoding == FT_ENCODING_MS_SYMBOL)
3180 {
3181 found = charmap;
3182 break;
3183 }
3184 }
3185 }
3186 if (!found)
3187 {
3188 DPRINT1("WARNING: Could not find desired charmap!\n");
3189 }
3190 else
3191 {
3192 DPRINT("Found charmap encoding: %i\n", found->encoding);
3193 error = FT_Set_Charmap(face, found);
3194 if (error)
3195 {
3196 DPRINT1("WARNING: Could not set the charmap!\n");
3197 }
3198 }
3199 }
3200
3201 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3202
3203 error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
3204
3205 if (bDoLock)
3206 IntUnLockFreeType();
3207
3208 if (error)
3209 {
3210 DPRINT1("Error in setting pixel sizes: %d\n", error);
3211 return FALSE;
3212 }
3213
3214 return TRUE;
3215 }
3216
3217 static inline FT_UInt FASTCALL
3218 get_glyph_index_symbol(FT_Face ft_face, UINT glyph)
3219 {
3220 FT_UInt ret;
3221
3222 if (glyph < 0x100) glyph += 0xf000;
3223 /* there are a number of old pre-Unicode "broken" TTFs, which