[WIN32SS][FONT] Fix GetTextFace function and related (#829)
[reactos.git] / win32ss / gdi / ntgdi / freetype.c
1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/freetype.c
5 * PURPOSE: FreeType font engine interface
6 * PROGRAMMERS: Copyright 2001 Huw D M Davies for CodeWeavers.
7 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
8 * Copyright 2016-2018 Katayama Hirofumi MZ.
9 */
10
11 /** Includes ******************************************************************/
12
13 #include <win32k.h>
14
15 #include FT_GLYPH_H
16 #include FT_TYPE1_TABLES_H
17 #include FT_TRUETYPE_TABLES_H
18 #include FT_TRUETYPE_TAGS_H
19 #include FT_TRIGONOMETRY_H
20 #include FT_BITMAP_H
21 #include FT_OUTLINE_H
22 #include FT_WINFONTS_H
23 #include FT_SFNT_NAMES_H
24 #include FT_SYNTHESIS_H
25 #include FT_TRUETYPE_IDS_H
26
27 #ifndef FT_INTERNAL_INTERNAL_H
28 #define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h>
29 #include FT_INTERNAL_INTERNAL_H
30 #endif
31 #include FT_INTERNAL_TRUETYPE_TYPES_H
32
33 #include <gdi/eng/floatobj.h>
34 #include "font.h"
35
36 #define NDEBUG
37 #include <debug.h>
38
39 /* TPMF_FIXED_PITCH is confusing; brain-dead api */
40 #ifndef _TMPF_VARIABLE_PITCH
41 #define _TMPF_VARIABLE_PITCH TMPF_FIXED_PITCH
42 #endif
43
44 extern const MATRIX gmxWorldToDeviceDefault;
45 extern const MATRIX gmxWorldToPageDefault;
46
47 /* HACK!! Fix XFORMOBJ then use 1:16 / 16:1 */
48 #define gmxWorldToDeviceDefault gmxWorldToPageDefault
49
50 FT_Library g_FreeTypeLibrary;
51
52 /* special font names */
53 static const UNICODE_STRING g_MarlettW = RTL_CONSTANT_STRING(L"Marlett");
54
55 /* registry */
56 static UNICODE_STRING g_FontRegPath =
57 RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
58
59
60 /* The FreeType library is not thread safe, so we have
61 to serialize access to it */
62 static PFAST_MUTEX g_FreeTypeLock;
63
64 static LIST_ENTRY g_FontListHead;
65 static PFAST_MUTEX g_FontListLock;
66 static BOOL g_RenderingEnabled = TRUE;
67
68 #define IntLockGlobalFonts() \
69 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FontListLock)
70
71 #define IntUnLockGlobalFonts() \
72 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FontListLock)
73
74 #define ASSERT_GLOBALFONTS_LOCK_HELD() \
75 ASSERT(g_FontListLock->Owner == KeGetCurrentThread())
76
77 #define IntLockFreeType() \
78 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FreeTypeLock)
79
80 #define IntUnLockFreeType() \
81 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FreeTypeLock)
82
83 #define ASSERT_FREETYPE_LOCK_HELD() \
84 ASSERT(g_FreeTypeLock->Owner == KeGetCurrentThread())
85
86 #define ASSERT_FREETYPE_LOCK_NOT_HELD() \
87 ASSERT(g_FreeTypeLock->Owner != KeGetCurrentThread())
88
89 #define MAX_FONT_CACHE 256
90
91 static LIST_ENTRY g_FontCacheListHead;
92 static UINT g_FontCacheNumEntries;
93
94 static PWCHAR g_ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */
95 {
96 L"Western", /* 00 */
97 L"Central_European",
98 L"Cyrillic",
99 L"Greek",
100 L"Turkish",
101 L"Hebrew",
102 L"Arabic",
103 L"Baltic",
104 L"Vietnamese", /* 08 */
105 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */
106 L"Thai",
107 L"Japanese",
108 L"CHINESE_GB2312",
109 L"Hangul",
110 L"CHINESE_BIG5",
111 L"Hangul(Johab)",
112 NULL, NULL, /* 23 */
113 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
114 L"Symbol" /* 31 */
115 };
116
117 /*
118 * For TranslateCharsetInfo
119 */
120 #define CP_SYMBOL 42
121 #define MAXTCIINDEX 32
122 static const CHARSETINFO g_FontTci[MAXTCIINDEX] =
123 {
124 /* ANSI */
125 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
126 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
127 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
128 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
129 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
130 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
131 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
132 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
133 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
134 /* reserved by ANSI */
135 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
136 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
137 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
138 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
139 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
140 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
141 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
142 /* ANSI and OEM */
143 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
144 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
145 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
146 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
147 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
148 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
149 /* Reserved for alternate ANSI and OEM */
150 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
151 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
152 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
153 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
154 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
155 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
157 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
158 /* Reserved for system */
159 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
160 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
161 };
162
163 #ifndef CP_OEMCP
164 #define CP_OEMCP 1
165 #define CP_MACCP 2
166 #endif
167
168 /* Get charset from specified codepage.
169 g_FontTci is used also in TranslateCharsetInfo. */
170 BYTE FASTCALL IntCharSetFromCodePage(UINT uCodePage)
171 {
172 UINT i;
173
174 if (uCodePage == CP_OEMCP)
175 return OEM_CHARSET;
176
177 if (uCodePage == CP_MACCP)
178 return MAC_CHARSET;
179
180 for (i = 0; i < MAXTCIINDEX; ++i)
181 {
182 if (g_FontTci[i].ciACP == 0)
183 continue;
184
185 if (g_FontTci[i].ciACP == uCodePage)
186 return g_FontTci[i].ciCharset;
187 }
188
189 return DEFAULT_CHARSET;
190 }
191
192 /* list head */
193 static RTL_STATIC_LIST_HEAD(g_FontSubstListHead);
194
195 static void
196 SharedMem_AddRef(PSHARED_MEM Ptr)
197 {
198 ASSERT_FREETYPE_LOCK_HELD();
199
200 ++Ptr->RefCount;
201 }
202
203 static void
204 SharedFaceCache_Init(PSHARED_FACE_CACHE Cache)
205 {
206 Cache->OutlineRequiredSize = 0;
207 RtlInitUnicodeString(&Cache->FontFamily, NULL);
208 RtlInitUnicodeString(&Cache->FullName, NULL);
209 }
210
211 static PSHARED_FACE
212 SharedFace_Create(FT_Face Face, PSHARED_MEM Memory)
213 {
214 PSHARED_FACE Ptr;
215 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
216 if (Ptr)
217 {
218 Ptr->Face = Face;
219 Ptr->RefCount = 1;
220 Ptr->Memory = Memory;
221 SharedFaceCache_Init(&Ptr->EnglishUS);
222 SharedFaceCache_Init(&Ptr->UserLanguage);
223
224 SharedMem_AddRef(Memory);
225 DPRINT("Creating SharedFace for %s\n", Face->family_name ? Face->family_name : "<NULL>");
226 }
227 return Ptr;
228 }
229
230 static PSHARED_MEM
231 SharedMem_Create(PBYTE Buffer, ULONG BufferSize, BOOL IsMapping)
232 {
233 PSHARED_MEM Ptr;
234 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_MEM), TAG_FONT);
235 if (Ptr)
236 {
237 Ptr->Buffer = Buffer;
238 Ptr->BufferSize = BufferSize;
239 Ptr->RefCount = 1;
240 Ptr->IsMapping = IsMapping;
241 DPRINT("Creating SharedMem for %p (%i, %p)\n", Buffer, IsMapping, Ptr);
242 }
243 return Ptr;
244 }
245
246 static void
247 SharedFace_AddRef(PSHARED_FACE Ptr)
248 {
249 ASSERT_FREETYPE_LOCK_HELD();
250
251 ++Ptr->RefCount;
252 }
253
254 static void
255 RemoveCachedEntry(PFONT_CACHE_ENTRY Entry)
256 {
257 ASSERT_FREETYPE_LOCK_HELD();
258
259 FT_Done_Glyph((FT_Glyph)Entry->BitmapGlyph);
260 RemoveEntryList(&Entry->ListEntry);
261 ExFreePoolWithTag(Entry, TAG_FONT);
262 g_FontCacheNumEntries--;
263 ASSERT(g_FontCacheNumEntries <= MAX_FONT_CACHE);
264 }
265
266 static void
267 RemoveCacheEntries(FT_Face Face)
268 {
269 PLIST_ENTRY CurrentEntry, NextEntry;
270 PFONT_CACHE_ENTRY FontEntry;
271
272 ASSERT_FREETYPE_LOCK_HELD();
273
274 for (CurrentEntry = g_FontCacheListHead.Flink;
275 CurrentEntry != &g_FontCacheListHead;
276 CurrentEntry = NextEntry)
277 {
278 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
279 NextEntry = CurrentEntry->Flink;
280
281 if (FontEntry->Face == Face)
282 {
283 RemoveCachedEntry(FontEntry);
284 }
285 }
286 }
287
288 static void SharedMem_Release(PSHARED_MEM Ptr)
289 {
290 ASSERT_FREETYPE_LOCK_HELD();
291 ASSERT(Ptr->RefCount > 0);
292
293 if (Ptr->RefCount <= 0)
294 return;
295
296 --Ptr->RefCount;
297 if (Ptr->RefCount == 0)
298 {
299 DPRINT("Releasing SharedMem for %p (%i, %p)\n", Ptr->Buffer, Ptr->IsMapping, Ptr);
300 if (Ptr->IsMapping)
301 MmUnmapViewInSystemSpace(Ptr->Buffer);
302 else
303 ExFreePoolWithTag(Ptr->Buffer, TAG_FONT);
304 ExFreePoolWithTag(Ptr, TAG_FONT);
305 }
306 }
307
308 static void
309 SharedFaceCache_Release(PSHARED_FACE_CACHE Cache)
310 {
311 RtlFreeUnicodeString(&Cache->FontFamily);
312 RtlFreeUnicodeString(&Cache->FullName);
313 }
314
315 static void
316 SharedFace_Release(PSHARED_FACE Ptr)
317 {
318 IntLockFreeType();
319 ASSERT(Ptr->RefCount > 0);
320
321 if (Ptr->RefCount <= 0)
322 return;
323
324 --Ptr->RefCount;
325 if (Ptr->RefCount == 0)
326 {
327 DPRINT("Releasing SharedFace for %s\n", Ptr->Face->family_name ? Ptr->Face->family_name : "<NULL>");
328 RemoveCacheEntries(Ptr->Face);
329 FT_Done_Face(Ptr->Face);
330 SharedMem_Release(Ptr->Memory);
331 SharedFaceCache_Release(&Ptr->EnglishUS);
332 SharedFaceCache_Release(&Ptr->UserLanguage);
333 ExFreePoolWithTag(Ptr, TAG_FONT);
334 }
335 IntUnLockFreeType();
336 }
337
338
339 /*
340 * IntLoadFontSubstList --- loads the list of font substitutes
341 */
342 BOOL FASTCALL
343 IntLoadFontSubstList(PLIST_ENTRY pHead)
344 {
345 NTSTATUS Status;
346 HANDLE KeyHandle;
347 OBJECT_ATTRIBUTES ObjectAttributes;
348 KEY_FULL_INFORMATION KeyFullInfo;
349 ULONG i, Length;
350 UNICODE_STRING FromW, ToW;
351 BYTE InfoBuffer[128];
352 PKEY_VALUE_FULL_INFORMATION pInfo;
353 BYTE CharSets[FONTSUBST_FROM_AND_TO];
354 LPWSTR pch;
355 PFONTSUBST_ENTRY pEntry;
356 BOOLEAN Success;
357
358 /* the FontSubstitutes registry key */
359 static UNICODE_STRING FontSubstKey =
360 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\"
361 L"Microsoft\\Windows NT\\CurrentVersion\\"
362 L"FontSubstitutes");
363
364 /* open registry key */
365 InitializeObjectAttributes(&ObjectAttributes, &FontSubstKey,
366 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
367 NULL, NULL);
368 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
369 if (!NT_SUCCESS(Status))
370 {
371 DPRINT("ZwOpenKey failed: 0x%08X\n", Status);
372 return FALSE; /* failure */
373 }
374
375 /* query count of values */
376 Status = ZwQueryKey(KeyHandle, KeyFullInformation,
377 &KeyFullInfo, sizeof(KeyFullInfo), &Length);
378 if (!NT_SUCCESS(Status))
379 {
380 DPRINT("ZwQueryKey failed: 0x%08X\n", Status);
381 ZwClose(KeyHandle);
382 return FALSE; /* failure */
383 }
384
385 /* for each value */
386 for (i = 0; i < KeyFullInfo.Values; ++i)
387 {
388 /* get value name */
389 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
390 InfoBuffer, sizeof(InfoBuffer), &Length);
391 if (!NT_SUCCESS(Status))
392 {
393 DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status);
394 break; /* failure */
395 }
396
397 /* create FromW string */
398 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
399 Length = pInfo->NameLength / sizeof(WCHAR);
400 pInfo->Name[Length] = UNICODE_NULL; /* truncate */
401 Success = RtlCreateUnicodeString(&FromW, pInfo->Name);
402 if (!Success)
403 {
404 Status = STATUS_INSUFFICIENT_RESOURCES;
405 DPRINT("RtlCreateUnicodeString failed\n");
406 break; /* failure */
407 }
408
409 /* query value */
410 Status = ZwQueryValueKey(KeyHandle, &FromW, KeyValueFullInformation,
411 InfoBuffer, sizeof(InfoBuffer), &Length);
412 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
413 if (!NT_SUCCESS(Status) || !pInfo->DataLength)
414 {
415 DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status);
416 RtlFreeUnicodeString(&FromW);
417 break; /* failure */
418 }
419
420 /* create ToW string */
421 pch = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
422 Length = pInfo->DataLength / sizeof(WCHAR);
423 pch[Length] = UNICODE_NULL; /* truncate */
424 Success = RtlCreateUnicodeString(&ToW, pch);
425 if (!Success)
426 {
427 Status = STATUS_INSUFFICIENT_RESOURCES;
428 DPRINT("RtlCreateUnicodeString failed\n");
429 RtlFreeUnicodeString(&FromW);
430 break; /* failure */
431 }
432
433 /* does charset exist? (from) */
434 CharSets[FONTSUBST_FROM] = DEFAULT_CHARSET;
435 pch = wcsrchr(FromW.Buffer, L',');
436 if (pch)
437 {
438 /* truncate */
439 *pch = UNICODE_NULL;
440 FromW.Length = (pch - FromW.Buffer) * sizeof(WCHAR);
441 /* parse charset number */
442 CharSets[FONTSUBST_FROM] = (BYTE)_wtoi(pch + 1);
443 }
444
445 /* does charset exist? (to) */
446 CharSets[FONTSUBST_TO] = DEFAULT_CHARSET;
447 pch = wcsrchr(ToW.Buffer, L',');
448 if (pch)
449 {
450 /* truncate */
451 *pch = UNICODE_NULL;
452 ToW.Length = (pch - ToW.Buffer) * sizeof(WCHAR);
453 /* parse charset number */
454 CharSets[FONTSUBST_TO] = (BYTE)_wtoi(pch + 1);
455 }
456
457 /* is it identical? */
458 if (RtlEqualUnicodeString(&FromW, &ToW, TRUE) &&
459 CharSets[FONTSUBST_FROM] == CharSets[FONTSUBST_TO])
460 {
461 RtlFreeUnicodeString(&FromW);
462 RtlFreeUnicodeString(&ToW);
463 continue;
464 }
465
466 /* allocate an entry */
467 pEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONTSUBST_ENTRY), TAG_FONT);
468 if (pEntry == NULL)
469 {
470 DPRINT("ExAllocatePoolWithTag failed\n");
471 RtlFreeUnicodeString(&FromW);
472 RtlFreeUnicodeString(&ToW);
473 break; /* failure */
474 }
475
476 /* store to *pEntry */
477 pEntry->FontNames[FONTSUBST_FROM] = FromW;
478 pEntry->FontNames[FONTSUBST_TO] = ToW;
479 pEntry->CharSets[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
480 pEntry->CharSets[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
481
482 /* insert pEntry to *pHead */
483 InsertTailList(pHead, &pEntry->ListEntry);
484 }
485
486 /* close now */
487 ZwClose(KeyHandle);
488
489 return NT_SUCCESS(Status);
490 }
491
492 BOOL FASTCALL
493 InitFontSupport(VOID)
494 {
495 ULONG ulError;
496
497 InitializeListHead(&g_FontListHead);
498 InitializeListHead(&g_FontCacheListHead);
499 g_FontCacheNumEntries = 0;
500 /* Fast Mutexes must be allocated from non paged pool */
501 g_FontListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
502 if (g_FontListLock == NULL)
503 {
504 return FALSE;
505 }
506
507 ExInitializeFastMutex(g_FontListLock);
508 g_FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
509 if (g_FreeTypeLock == NULL)
510 {
511 return FALSE;
512 }
513 ExInitializeFastMutex(g_FreeTypeLock);
514
515 ulError = FT_Init_FreeType(&g_FreeTypeLibrary);
516 if (ulError)
517 {
518 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
519 return FALSE;
520 }
521
522 IntLoadSystemFonts();
523 IntLoadFontSubstList(&g_FontSubstListHead);
524
525 return TRUE;
526 }
527
528 VOID
529 FtSetCoordinateTransform(
530 FT_Face face,
531 PMATRIX pmx)
532 {
533 FT_Matrix ftmatrix;
534 FLOATOBJ efTemp;
535
536 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
537 efTemp = pmx->efM11;
538 FLOATOBJ_MulLong(&efTemp, 0x00010000);
539 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
540
541 efTemp = pmx->efM12;
542 FLOATOBJ_MulLong(&efTemp, 0x00010000);
543 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
544
545 efTemp = pmx->efM21;
546 FLOATOBJ_MulLong(&efTemp, 0x00010000);
547 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
548
549 efTemp = pmx->efM22;
550 FLOATOBJ_MulLong(&efTemp, 0x00010000);
551 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
552
553 /* Set the transformation matrix */
554 FT_Set_Transform(face, &ftmatrix, 0);
555 }
556
557 static BOOL
558 SubstituteFontByList(PLIST_ENTRY pHead,
559 PUNICODE_STRING pOutputName,
560 PUNICODE_STRING pInputName,
561 BYTE RequestedCharSet,
562 BYTE CharSetMap[FONTSUBST_FROM_AND_TO])
563 {
564 PLIST_ENTRY pListEntry;
565 PFONTSUBST_ENTRY pSubstEntry;
566 BYTE CharSets[FONTSUBST_FROM_AND_TO];
567
568 CharSetMap[FONTSUBST_FROM] = DEFAULT_CHARSET;
569 CharSetMap[FONTSUBST_TO] = RequestedCharSet;
570
571 /* for each list entry */
572 for (pListEntry = pHead->Flink;
573 pListEntry != pHead;
574 pListEntry = pListEntry->Flink)
575 {
576 pSubstEntry =
577 (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_ENTRY, ListEntry);
578
579 CharSets[FONTSUBST_FROM] = pSubstEntry->CharSets[FONTSUBST_FROM];
580
581 if (CharSets[FONTSUBST_FROM] != DEFAULT_CHARSET &&
582 CharSets[FONTSUBST_FROM] != RequestedCharSet)
583 {
584 continue; /* not matched */
585 }
586
587 /* does charset number exist? (to) */
588 if (pSubstEntry->CharSets[FONTSUBST_TO] != DEFAULT_CHARSET)
589 {
590 CharSets[FONTSUBST_TO] = pSubstEntry->CharSets[FONTSUBST_TO];
591 }
592 else
593 {
594 CharSets[FONTSUBST_TO] = RequestedCharSet;
595 }
596
597 /* does font name match? */
598 if (!RtlEqualUnicodeString(&pSubstEntry->FontNames[FONTSUBST_FROM],
599 pInputName, TRUE))
600 {
601 continue; /* not matched */
602 }
603
604 /* update *pOutputName */
605 *pOutputName = pSubstEntry->FontNames[FONTSUBST_TO];
606
607 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
608 {
609 /* update CharSetMap */
610 CharSetMap[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
611 CharSetMap[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
612 }
613 return TRUE; /* success */
614 }
615
616 return FALSE;
617 }
618
619 static BOOL
620 SubstituteFontRecurse(LOGFONTW* pLogFont)
621 {
622 UINT RecurseCount = 5;
623 UNICODE_STRING OutputNameW = { 0 };
624 BYTE CharSetMap[FONTSUBST_FROM_AND_TO];
625 BOOL Found;
626 UNICODE_STRING InputNameW;
627
628 if (pLogFont->lfFaceName[0] == UNICODE_NULL)
629 return FALSE;
630
631 RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
632
633 while (RecurseCount-- > 0)
634 {
635 Found = SubstituteFontByList(&g_FontSubstListHead,
636 &OutputNameW, &InputNameW,
637 pLogFont->lfCharSet, CharSetMap);
638 if (!Found)
639 break;
640
641 RtlStringCchCopyW(pLogFont->lfFaceName, LF_FACESIZE, OutputNameW.Buffer);
642
643 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
644 CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
645 {
646 pLogFont->lfCharSet = CharSetMap[FONTSUBST_TO];
647 }
648 }
649
650 return TRUE; /* success */
651 }
652
653 /*
654 * IntLoadSystemFonts
655 *
656 * Search the system font directory and adds each font found.
657 */
658 VOID FASTCALL
659 IntLoadSystemFonts(VOID)
660 {
661 OBJECT_ATTRIBUTES ObjectAttributes;
662 UNICODE_STRING Directory, FileName, TempString;
663 IO_STATUS_BLOCK Iosb;
664 HANDLE hDirectory;
665 BYTE *DirInfoBuffer;
666 PFILE_DIRECTORY_INFORMATION DirInfo;
667 BOOLEAN bRestartScan = TRUE;
668 NTSTATUS Status;
669 INT i;
670 static UNICODE_STRING SearchPatterns[] =
671 {
672 RTL_CONSTANT_STRING(L"*.ttf"),
673 RTL_CONSTANT_STRING(L"*.ttc"),
674 RTL_CONSTANT_STRING(L"*.otf"),
675 RTL_CONSTANT_STRING(L"*.otc"),
676 RTL_CONSTANT_STRING(L"*.fon"),
677 RTL_CONSTANT_STRING(L"*.fnt")
678 };
679
680 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
681
682 InitializeObjectAttributes(
683 &ObjectAttributes,
684 &Directory,
685 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
686 NULL,
687 NULL);
688
689 Status = ZwOpenFile(
690 &hDirectory,
691 SYNCHRONIZE | FILE_LIST_DIRECTORY,
692 &ObjectAttributes,
693 &Iosb,
694 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
695 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
696
697 if (NT_SUCCESS(Status))
698 {
699 for (i = 0; i < _countof(SearchPatterns); ++i)
700 {
701 DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
702 if (DirInfoBuffer == NULL)
703 {
704 ZwClose(hDirectory);
705 return;
706 }
707
708 FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
709 if (FileName.Buffer == NULL)
710 {
711 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
712 ZwClose(hDirectory);
713 return;
714 }
715 FileName.Length = 0;
716 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
717
718 while (1)
719 {
720 Status = ZwQueryDirectoryFile(
721 hDirectory,
722 NULL,
723 NULL,
724 NULL,
725 &Iosb,
726 DirInfoBuffer,
727 0x4000,
728 FileDirectoryInformation,
729 FALSE,
730 &SearchPatterns[i],
731 bRestartScan);
732
733 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
734 {
735 break;
736 }
737
738 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
739 while (1)
740 {
741 TempString.Buffer = DirInfo->FileName;
742 TempString.Length =
743 TempString.MaximumLength = DirInfo->FileNameLength;
744 RtlCopyUnicodeString(&FileName, &Directory);
745 RtlAppendUnicodeStringToString(&FileName, &TempString);
746 IntGdiAddFontResource(&FileName, 0);
747 if (DirInfo->NextEntryOffset == 0)
748 break;
749 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
750 }
751
752 bRestartScan = FALSE;
753 }
754
755 ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
756 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
757 }
758 ZwClose(hDirectory);
759 }
760 }
761
762 static BYTE
763 ItalicFromStyle(const char *style_name)
764 {
765 if (style_name == NULL || style_name[0] == 0)
766 return FALSE;
767 if (strstr(style_name, "Italic") != NULL)
768 return TRUE;
769 if (strstr(style_name, "Oblique") != NULL)
770 return TRUE;
771 return FALSE;
772 }
773
774 static LONG
775 WeightFromStyle(const char *style_name)
776 {
777 if (style_name == NULL || style_name[0] == 0)
778 return FW_NORMAL;
779 if (strstr(style_name, "Regular") != NULL)
780 return FW_REGULAR;
781 if (strstr(style_name, "Normal") != NULL)
782 return FW_NORMAL;
783 if (strstr(style_name, "SemiBold") != NULL)
784 return FW_SEMIBOLD;
785 if (strstr(style_name, "UltraBold") != NULL)
786 return FW_ULTRABOLD;
787 if (strstr(style_name, "DemiBold") != NULL)
788 return FW_DEMIBOLD;
789 if (strstr(style_name, "ExtraBold") != NULL)
790 return FW_EXTRABOLD;
791 if (strstr(style_name, "Bold") != NULL)
792 return FW_BOLD;
793 if (strstr(style_name, "UltraLight") != NULL)
794 return FW_ULTRALIGHT;
795 if (strstr(style_name, "ExtraLight") != NULL)
796 return FW_EXTRALIGHT;
797 if (strstr(style_name, "Light") != NULL)
798 return FW_LIGHT;
799 if (strstr(style_name, "Hairline") != NULL)
800 return 50;
801 if (strstr(style_name, "Book") != NULL)
802 return 350;
803 if (strstr(style_name, "ExtraBlack") != NULL)
804 return 950;
805 if (strstr(style_name, "UltraBlack") != NULL)
806 return 1000;
807 if (strstr(style_name, "Black") != NULL)
808 return FW_BLACK;
809 if (strstr(style_name, "Medium") != NULL)
810 return FW_MEDIUM;
811 if (strstr(style_name, "Thin") != NULL)
812 return FW_THIN;
813 if (strstr(style_name, "Heavy") != NULL)
814 return FW_HEAVY;
815 return FW_NORMAL;
816 }
817
818 static FT_Error
819 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight);
820
821 static INT FASTCALL
822 IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
823 PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
824 {
825 FT_Error Error;
826 PFONT_ENTRY Entry;
827 FONT_ENTRY_MEM* PrivateEntry = NULL;
828 FONTGDI * FontGDI;
829 NTSTATUS Status;
830 FT_Face Face;
831 ANSI_STRING AnsiFaceName;
832 FT_WinFNT_HeaderRec WinFNT;
833 INT FaceCount = 0, CharSetCount = 0;
834 PUNICODE_STRING pFileName = pLoadFont->pFileName;
835 DWORD Characteristics = pLoadFont->Characteristics;
836 PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
837 TT_OS2 * pOS2;
838 INT BitIndex;
839 FT_UShort os2_version;
840 FT_ULong os2_ulCodePageRange1;
841 FT_UShort os2_usWeightClass;
842
843 if (SharedFace == NULL && CharSetIndex == -1)
844 {
845 /* load a face from memory */
846 IntLockFreeType();
847 Error = FT_New_Memory_Face(
848 g_FreeTypeLibrary,
849 pLoadFont->Memory->Buffer,
850 pLoadFont->Memory->BufferSize,
851 ((FontIndex != -1) ? FontIndex : 0),
852 &Face);
853
854 if (!Error)
855 SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
856
857 IntUnLockFreeType();
858
859 if (!Error && FT_IS_SFNT(Face))
860 pLoadFont->IsTrueType = TRUE;
861
862 if (Error || SharedFace == NULL)
863 {
864 if (SharedFace)
865 SharedFace_Release(SharedFace);
866
867 if (Error == FT_Err_Unknown_File_Format)
868 DPRINT1("Unknown font file format\n");
869 else
870 DPRINT1("Error reading font (error code: %d)\n", Error);
871 return 0; /* failure */
872 }
873 }
874 else
875 {
876 Face = SharedFace->Face;
877 IntLockFreeType();
878 SharedFace_AddRef(SharedFace);
879 IntUnLockFreeType();
880 }
881
882 /* allocate a FONT_ENTRY */
883 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
884 if (!Entry)
885 {
886 SharedFace_Release(SharedFace);
887 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
888 return 0; /* failure */
889 }
890
891 /* allocate a FONTGDI */
892 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
893 if (!FontGDI)
894 {
895 SharedFace_Release(SharedFace);
896 ExFreePoolWithTag(Entry, TAG_FONT);
897 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
898 return 0; /* failure */
899 }
900
901 /* set file name */
902 if (pFileName)
903 {
904 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool,
905 pFileName->Length + sizeof(UNICODE_NULL),
906 GDITAG_PFF);
907 if (FontGDI->Filename == NULL)
908 {
909 EngFreeMem(FontGDI);
910 SharedFace_Release(SharedFace);
911 ExFreePoolWithTag(Entry, TAG_FONT);
912 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
913 return 0; /* failure */
914 }
915 RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
916 FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
917 }
918 else
919 {
920 FontGDI->Filename = NULL;
921
922 PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT);
923 if (!PrivateEntry)
924 {
925 if (FontGDI->Filename)
926 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
927 EngFreeMem(FontGDI);
928 SharedFace_Release(SharedFace);
929 ExFreePoolWithTag(Entry, TAG_FONT);
930 return 0;
931 }
932
933 PrivateEntry->Entry = Entry;
934 if (pLoadFont->PrivateEntry)
935 {
936 InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry);
937 }
938 else
939 {
940 InitializeListHead(&PrivateEntry->ListEntry);
941 pLoadFont->PrivateEntry = PrivateEntry;
942 }
943 }
944
945 /* set face */
946 FontGDI->SharedFace = SharedFace;
947 FontGDI->CharSet = ANSI_CHARSET;
948 FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name);
949 FontGDI->RequestItalic = FALSE;
950 FontGDI->OriginalWeight = WeightFromStyle(Face->style_name);
951 FontGDI->RequestWeight = FW_NORMAL;
952
953 RtlInitAnsiString(&AnsiFaceName, Face->family_name);
954 Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
955 if (!NT_SUCCESS(Status))
956 {
957 if (PrivateEntry)
958 {
959 if (pLoadFont->PrivateEntry == PrivateEntry)
960 {
961 pLoadFont->PrivateEntry = NULL;
962 }
963 else
964 {
965 RemoveEntryList(&PrivateEntry->ListEntry);
966 }
967 ExFreePoolWithTag(PrivateEntry, TAG_FONT);
968 }
969 if (FontGDI->Filename)
970 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
971 EngFreeMem(FontGDI);
972 SharedFace_Release(SharedFace);
973 ExFreePoolWithTag(Entry, TAG_FONT);
974 return 0;
975 }
976
977 os2_version = 0;
978 IntLockFreeType();
979 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
980 if (pOS2)
981 {
982 os2_version = pOS2->version;
983 os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
984 os2_usWeightClass = pOS2->usWeightClass;
985 }
986 IntUnLockFreeType();
987
988 if (pOS2 && os2_version >= 1)
989 {
990 /* get charset and weight from OS/2 header */
991
992 /* Make sure we do not use this pointer anymore */
993 pOS2 = NULL;
994
995 for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
996 {
997 if (os2_ulCodePageRange1 & (1 << BitIndex))
998 {
999 if (g_FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
1000 continue;
1001
1002 if ((CharSetIndex == -1 && CharSetCount == 0) ||
1003 CharSetIndex == CharSetCount)
1004 {
1005 FontGDI->CharSet = g_FontTci[BitIndex].ciCharset;
1006 }
1007
1008 ++CharSetCount;
1009 }
1010 }
1011
1012 /* set actual weight */
1013 FontGDI->OriginalWeight = os2_usWeightClass;
1014 }
1015 else
1016 {
1017 /* get charset from WinFNT header */
1018 IntLockFreeType();
1019 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
1020 if (!Error)
1021 {
1022 FontGDI->CharSet = WinFNT.charset;
1023 }
1024 IntUnLockFreeType();
1025 }
1026
1027 /* FIXME: CharSet is invalid on Marlett */
1028 if (RtlEqualUnicodeString(&Entry->FaceName, &g_MarlettW, TRUE))
1029 {
1030 FontGDI->CharSet = SYMBOL_CHARSET;
1031 }
1032
1033 ++FaceCount;
1034 DPRINT("Font loaded: %s (%s)\n",
1035 Face->family_name ? Face->family_name : "<NULL>",
1036 Face->style_name ? Face->style_name : "<NULL>");
1037 DPRINT("Num glyphs: %d\n", Face->num_glyphs);
1038 DPRINT("CharSet: %d\n", FontGDI->CharSet);
1039
1040 IntLockFreeType();
1041 IntRequestFontSize(NULL, FontGDI, 0, 0);
1042 IntUnLockFreeType();
1043
1044 /* Add this font resource to the font table */
1045 Entry->Font = FontGDI;
1046 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
1047
1048 if (Characteristics & FR_PRIVATE)
1049 {
1050 /* private font */
1051 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1052 IntLockProcessPrivateFonts(Win32Process);
1053 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
1054 IntUnLockProcessPrivateFonts(Win32Process);
1055 }
1056 else
1057 {
1058 /* global font */
1059 IntLockGlobalFonts();
1060 InsertTailList(&g_FontListHead, &Entry->ListEntry);
1061 IntUnLockGlobalFonts();
1062 }
1063
1064 if (FontIndex == -1)
1065 {
1066 if (FT_IS_SFNT(Face))
1067 {
1068 TT_Face TrueType = (TT_Face)Face;
1069 if (TrueType->ttc_header.count > 1)
1070 {
1071 FT_Long i;
1072 for (i = 1; i < TrueType->ttc_header.count; ++i)
1073 {
1074 FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
1075 }
1076 }
1077 }
1078 FontIndex = 0;
1079 }
1080
1081 if (CharSetIndex == -1)
1082 {
1083 INT i;
1084
1085 if (pLoadFont->RegValueName.Length == 0)
1086 {
1087 RtlCreateUnicodeString(pValueName, Entry->FaceName.Buffer);
1088 }
1089 else
1090 {
1091 UNICODE_STRING NewString;
1092 USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + Entry->FaceName.Length;
1093 NewString.Length = 0;
1094 NewString.MaximumLength = Length + sizeof(WCHAR);
1095 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1096 NewString.MaximumLength,
1097 TAG_USTR);
1098 NewString.Buffer[0] = UNICODE_NULL;
1099
1100 RtlAppendUnicodeStringToString(&NewString, pValueName);
1101 RtlAppendUnicodeToString(&NewString, L" & ");
1102 RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
1103
1104 RtlFreeUnicodeString(pValueName);
1105 *pValueName = NewString;
1106 }
1107
1108 for (i = 1; i < CharSetCount; ++i)
1109 {
1110 /* Do not count charsets towards 'faces' loaded */
1111 IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
1112 }
1113 }
1114
1115 return FaceCount; /* number of loaded faces */
1116 }
1117
1118 /*
1119 * IntGdiAddFontResource
1120 *
1121 * Adds the font resource from the specified file to the system.
1122 */
1123
1124 INT FASTCALL
1125 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
1126 {
1127 NTSTATUS Status;
1128 HANDLE FileHandle;
1129 PVOID Buffer = NULL;
1130 IO_STATUS_BLOCK Iosb;
1131 PVOID SectionObject;
1132 SIZE_T ViewSize = 0;
1133 LARGE_INTEGER SectionSize;
1134 OBJECT_ATTRIBUTES ObjectAttributes;
1135 GDI_LOAD_FONT LoadFont;
1136 INT FontCount;
1137 HANDLE KeyHandle;
1138 static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
1139
1140 /* Open the font file */
1141 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
1142 Status = ZwOpenFile(
1143 &FileHandle,
1144 FILE_GENERIC_READ | SYNCHRONIZE,
1145 &ObjectAttributes,
1146 &Iosb,
1147 FILE_SHARE_READ,
1148 FILE_SYNCHRONOUS_IO_NONALERT);
1149 if (!NT_SUCCESS(Status))
1150 {
1151 DPRINT("Could not load font file: %wZ\n", FileName);
1152 return 0;
1153 }
1154
1155 SectionSize.QuadPart = 0LL;
1156 Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
1157 NULL, &SectionSize, PAGE_READONLY,
1158 SEC_COMMIT, FileHandle, NULL);
1159 if (!NT_SUCCESS(Status))
1160 {
1161 DPRINT("Could not map file: %wZ\n", FileName);
1162 ZwClose(FileHandle);
1163 return 0;
1164 }
1165 ZwClose(FileHandle);
1166
1167 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
1168 if (!NT_SUCCESS(Status))
1169 {
1170 DPRINT("Could not map file: %wZ\n", FileName);
1171 ObDereferenceObject(SectionObject);
1172 return 0;
1173 }
1174
1175 LoadFont.pFileName = FileName;
1176 LoadFont.Memory = SharedMem_Create(Buffer, ViewSize, TRUE);
1177 LoadFont.Characteristics = Characteristics;
1178 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1179 LoadFont.IsTrueType = FALSE;
1180 LoadFont.PrivateEntry = NULL;
1181 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1182
1183 ObDereferenceObject(SectionObject);
1184
1185 /* Release our copy */
1186 IntLockFreeType();
1187 SharedMem_Release(LoadFont.Memory);
1188 IntUnLockFreeType();
1189
1190 if (FontCount > 0)
1191 {
1192 if (LoadFont.IsTrueType)
1193 {
1194 /* append " (TrueType)" */
1195 UNICODE_STRING NewString;
1196 USHORT Length;
1197
1198 Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length;
1199 NewString.Length = 0;
1200 NewString.MaximumLength = Length + sizeof(WCHAR);
1201 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1202 NewString.MaximumLength,
1203 TAG_USTR);
1204 NewString.Buffer[0] = UNICODE_NULL;
1205
1206 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
1207 RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
1208 RtlFreeUnicodeString(&LoadFont.RegValueName);
1209 LoadFont.RegValueName = NewString;
1210 }
1211
1212 /* registry */
1213 InitializeObjectAttributes(&ObjectAttributes, &g_FontRegPath,
1214 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1215 NULL, NULL);
1216 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
1217 if (NT_SUCCESS(Status))
1218 {
1219 SIZE_T DataSize;
1220 LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
1221 if (pFileName)
1222 {
1223 pFileName++;
1224 DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
1225 ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
1226 pFileName, DataSize);
1227 }
1228 ZwClose(KeyHandle);
1229 }
1230 }
1231 RtlFreeUnicodeString(&LoadFont.RegValueName);
1232
1233 return FontCount;
1234 }
1235
1236 HANDLE FASTCALL
1237 IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
1238 {
1239 GDI_LOAD_FONT LoadFont;
1240 FONT_ENTRY_COLL_MEM* EntryCollection;
1241 INT FaceCount;
1242 HANDLE Ret = 0;
1243
1244 PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
1245
1246 if (!BufferCopy)
1247 {
1248 *pNumAdded = 0;
1249 return NULL;
1250 }
1251 memcpy(BufferCopy, Buffer, dwSize);
1252
1253 LoadFont.pFileName = NULL;
1254 LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
1255 LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
1256 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1257 LoadFont.IsTrueType = FALSE;
1258 LoadFont.PrivateEntry = NULL;
1259 FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1260
1261 RtlFreeUnicodeString(&LoadFont.RegValueName);
1262
1263 /* Release our copy */
1264 IntLockFreeType();
1265 SharedMem_Release(LoadFont.Memory);
1266 IntUnLockFreeType();
1267
1268 if (FaceCount > 0)
1269 {
1270 EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
1271 if (EntryCollection)
1272 {
1273 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1274 EntryCollection->Entry = LoadFont.PrivateEntry;
1275 IntLockProcessPrivateFonts(Win32Process);
1276 EntryCollection->Handle = ULongToHandle(++Win32Process->PrivateMemFontHandleCount);
1277 InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
1278 IntUnLockProcessPrivateFonts(Win32Process);
1279 Ret = EntryCollection->Handle;
1280 }
1281 }
1282 *pNumAdded = FaceCount;
1283
1284 return Ret;
1285 }
1286
1287 // FIXME: Add RemoveFontResource
1288
1289 static VOID FASTCALL
1290 CleanupFontEntry(PFONT_ENTRY FontEntry)
1291 {
1292 PFONTGDI FontGDI = FontEntry->Font;
1293 PSHARED_FACE SharedFace = FontGDI->SharedFace;
1294
1295 if (FontGDI->Filename)
1296 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1297
1298 EngFreeMem(FontGDI);
1299 SharedFace_Release(SharedFace);
1300 ExFreePoolWithTag(FontEntry, TAG_FONT);
1301 }
1302
1303 VOID FASTCALL
1304 IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
1305 {
1306 PLIST_ENTRY Entry;
1307 PFONT_ENTRY_MEM FontEntry;
1308
1309 while (!IsListEmpty(&Head->ListEntry))
1310 {
1311 Entry = RemoveHeadList(&Head->ListEntry);
1312 FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
1313
1314 CleanupFontEntry(FontEntry->Entry);
1315 ExFreePoolWithTag(FontEntry, TAG_FONT);
1316 }
1317
1318 CleanupFontEntry(Head->Entry);
1319 ExFreePoolWithTag(Head, TAG_FONT);
1320 }
1321
1322 static VOID FASTCALL
1323 UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)
1324 {
1325 PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
1326 PLIST_ENTRY ListEntry;
1327 RemoveEntryList(&Collection->ListEntry);
1328
1329 do {
1330 /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
1331 RemoveEntryList(&FontMemEntry->Entry->ListEntry);
1332
1333 ListEntry = FontMemEntry->ListEntry.Flink;
1334 FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
1335
1336 } while (FontMemEntry != Collection->Entry);
1337 }
1338
1339 BOOL FASTCALL
1340 IntGdiRemoveFontMemResource(HANDLE hMMFont)
1341 {
1342 PLIST_ENTRY Entry;
1343 PFONT_ENTRY_COLL_MEM CurrentEntry;
1344 PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
1345 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1346
1347 IntLockProcessPrivateFonts(Win32Process);
1348 for (Entry = Win32Process->PrivateMemFontListHead.Flink;
1349 Entry != &Win32Process->PrivateMemFontListHead;
1350 Entry = Entry->Flink)
1351 {
1352 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1353
1354 if (CurrentEntry->Handle == hMMFont)
1355 {
1356 EntryCollection = CurrentEntry;
1357 UnlinkFontMemCollection(CurrentEntry);
1358 break;
1359 }
1360 }
1361 IntUnLockProcessPrivateFonts(Win32Process);
1362
1363 if (EntryCollection)
1364 {
1365 IntGdiCleanupMemEntry(EntryCollection->Entry);
1366 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1367 return TRUE;
1368 }
1369 return FALSE;
1370 }
1371
1372
1373 VOID FASTCALL
1374 IntGdiCleanupPrivateFontsForProcess(VOID)
1375 {
1376 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1377 PLIST_ENTRY Entry;
1378 PFONT_ENTRY_COLL_MEM EntryCollection;
1379
1380 DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
1381 do {
1382 Entry = NULL;
1383 EntryCollection = NULL;
1384
1385 IntLockProcessPrivateFonts(Win32Process);
1386 if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
1387 {
1388 Entry = Win32Process->PrivateMemFontListHead.Flink;
1389 EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1390 UnlinkFontMemCollection(EntryCollection);
1391 }
1392 IntUnLockProcessPrivateFonts(Win32Process);
1393
1394 if (EntryCollection)
1395 {
1396 IntGdiCleanupMemEntry(EntryCollection->Entry);
1397 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1398 }
1399 else
1400 {
1401 /* No Mem fonts anymore, see if we have any other private fonts left */
1402 Entry = NULL;
1403 IntLockProcessPrivateFonts(Win32Process);
1404 if (!IsListEmpty(&Win32Process->PrivateFontListHead))
1405 {
1406 Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
1407 }
1408 IntUnLockProcessPrivateFonts(Win32Process);
1409
1410 if (Entry)
1411 {
1412 CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
1413 }
1414 }
1415
1416 } while (Entry);
1417 }
1418
1419 BOOL FASTCALL
1420 IntIsFontRenderingEnabled(VOID)
1421 {
1422 BOOL Ret = g_RenderingEnabled;
1423 HDC hDC;
1424
1425 hDC = IntGetScreenDC();
1426 if (hDC)
1427 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && g_RenderingEnabled;
1428
1429 return Ret;
1430 }
1431
1432 VOID FASTCALL
1433 IntEnableFontRendering(BOOL Enable)
1434 {
1435 g_RenderingEnabled = Enable;
1436 }
1437
1438 FT_Render_Mode FASTCALL
1439 IntGetFontRenderMode(LOGFONTW *logfont)
1440 {
1441 switch (logfont->lfQuality)
1442 {
1443 case ANTIALIASED_QUALITY:
1444 break;
1445 case NONANTIALIASED_QUALITY:
1446 return FT_RENDER_MODE_MONO;
1447 case DRAFT_QUALITY:
1448 return FT_RENDER_MODE_LIGHT;
1449 /* case CLEARTYPE_QUALITY:
1450 return FT_RENDER_MODE_LCD; */
1451 }
1452 return FT_RENDER_MODE_NORMAL;
1453 }
1454
1455
1456 NTSTATUS FASTCALL
1457 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
1458 {
1459 PLFONT plfont;
1460 LOGFONTW *plf;
1461
1462 plfont = LFONT_AllocFontWithHandle();
1463 if (!plfont)
1464 {
1465 return STATUS_NO_MEMORY;
1466 }
1467
1468 ExInitializePushLock(&plfont->lock);
1469 *NewFont = plfont->BaseObject.hHmgr;
1470 plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
1471 RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
1472 if (lf->lfEscapement != lf->lfOrientation)
1473 {
1474 /* This should really depend on whether GM_ADVANCED is set */
1475 plf->lfOrientation = plf->lfEscapement;
1476 }
1477 LFONT_UnlockFont(plfont);
1478
1479 return STATUS_SUCCESS;
1480 }
1481
1482 /*************************************************************************
1483 * TranslateCharsetInfo
1484 *
1485 * Fills a CHARSETINFO structure for a character set, code page, or
1486 * font. This allows making the correspondance between different labelings
1487 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
1488 * of the same encoding.
1489 *
1490 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
1491 * only one codepage should be set in *Src.
1492 *
1493 * RETURNS
1494 * TRUE on success, FALSE on failure.
1495 *
1496 */
1497 static BOOLEAN APIENTRY
1498 IntTranslateCharsetInfo(PDWORD Src, /* [in]
1499 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
1500 if flags == TCI_SRCCHARSET: a character set value
1501 if flags == TCI_SRCCODEPAGE: a code page value */
1502 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
1503 DWORD Flags /* [in] determines interpretation of lpSrc */)
1504 {
1505 int Index = 0;
1506
1507 switch (Flags)
1508 {
1509 case TCI_SRCFONTSIG:
1510 while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
1511 {
1512 Index++;
1513 }
1514 break;
1515 case TCI_SRCCODEPAGE:
1516 while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciACP)
1517 {
1518 Index++;
1519 }
1520 break;
1521 case TCI_SRCCHARSET:
1522 while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciCharset)
1523 {
1524 Index++;
1525 }
1526 break;
1527 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