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