[WIN32K] Fix NtGdiGetTextFaceW to report face name correctly (#173)
[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-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
52 /* special font names */
53 static const UNICODE_STRING MarlettW = RTL_CONSTANT_STRING(L"Marlett");
54
55 /* registry */
56 static UNICODE_STRING 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 FreeTypeLock;
63
64 static LIST_ENTRY FontListHead;
65 static PFAST_MUTEX FontListLock;
66 static BOOL RenderingEnabled = TRUE;
67
68 #define IntLockGlobalFonts \
69 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FontListLock)
70
71 #define IntUnLockGlobalFonts \
72 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
73
74 #define ASSERT_GLOBALFONTS_LOCK_HELD() \
75 ASSERT(FontListLock->Owner == KeGetCurrentThread())
76
77 #define IntLockFreeType \
78 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
79
80 #define IntUnLockFreeType \
81 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock)
82
83 #define ASSERT_FREETYPE_LOCK_HELD() \
84 ASSERT(FreeTypeLock->Owner == KeGetCurrentThread())
85
86 #define ASSERT_FREETYPE_LOCK_NOT_HELD() \
87 ASSERT(FreeTypeLock->Owner != KeGetCurrentThread())
88
89 #define MAX_FONT_CACHE 256
90
91 static LIST_ENTRY FontCacheListHead;
92 static UINT FontCacheNumEntries;
93
94 static PWCHAR 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 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 /* list head */
164 static RTL_STATIC_LIST_HEAD(FontSubstListHead);
165
166 static void
167 SharedMem_AddRef(PSHARED_MEM Ptr)
168 {
169 ASSERT_FREETYPE_LOCK_HELD();
170
171 ++Ptr->RefCount;
172 }
173
174 static void
175 SharedFaceCache_Init(PSHARED_FACE_CACHE Cache)
176 {
177 Cache->OutlineRequiredSize = 0;
178 RtlInitUnicodeString(&Cache->FontFamily, NULL);
179 RtlInitUnicodeString(&Cache->FullName, NULL);
180 }
181
182 static PSHARED_FACE
183 SharedFace_Create(FT_Face Face, PSHARED_MEM Memory)
184 {
185 PSHARED_FACE Ptr;
186 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
187 if (Ptr)
188 {
189 Ptr->Face = Face;
190 Ptr->RefCount = 1;
191 Ptr->Memory = Memory;
192 SharedFaceCache_Init(&Ptr->EnglishUS);
193 SharedFaceCache_Init(&Ptr->UserLanguage);
194
195 SharedMem_AddRef(Memory);
196 DPRINT("Creating SharedFace for %s\n", Face->family_name);
197 }
198 return Ptr;
199 }
200
201 static PSHARED_MEM
202 SharedMem_Create(PBYTE Buffer, ULONG BufferSize, BOOL IsMapping)
203 {
204 PSHARED_MEM Ptr;
205 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_MEM), TAG_FONT);
206 if (Ptr)
207 {
208 Ptr->Buffer = Buffer;
209 Ptr->BufferSize = BufferSize;
210 Ptr->RefCount = 1;
211 Ptr->IsMapping = IsMapping;
212 DPRINT("Creating SharedMem for %p (%i, %p)\n", Buffer, IsMapping, Ptr);
213 }
214 return Ptr;
215 }
216
217 static void
218 SharedFace_AddRef(PSHARED_FACE Ptr)
219 {
220 ASSERT_FREETYPE_LOCK_HELD();
221
222 ++Ptr->RefCount;
223 }
224
225 static void
226 RemoveCachedEntry(PFONT_CACHE_ENTRY Entry)
227 {
228 ASSERT_FREETYPE_LOCK_HELD();
229
230 FT_Done_Glyph((FT_Glyph)Entry->BitmapGlyph);
231 RemoveEntryList(&Entry->ListEntry);
232 ExFreePoolWithTag(Entry, TAG_FONT);
233 FontCacheNumEntries--;
234 ASSERT(FontCacheNumEntries <= MAX_FONT_CACHE);
235 }
236
237 static void
238 RemoveCacheEntries(FT_Face Face)
239 {
240 PLIST_ENTRY CurrentEntry;
241 PFONT_CACHE_ENTRY FontEntry;
242
243 ASSERT_FREETYPE_LOCK_HELD();
244
245 CurrentEntry = FontCacheListHead.Flink;
246 while (CurrentEntry != &FontCacheListHead)
247 {
248 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
249 CurrentEntry = CurrentEntry->Flink;
250
251 if (FontEntry->Face == Face)
252 {
253 RemoveCachedEntry(FontEntry);
254 }
255 }
256 }
257
258 static void SharedMem_Release(PSHARED_MEM Ptr)
259 {
260 ASSERT_FREETYPE_LOCK_HELD();
261 ASSERT(Ptr->RefCount > 0);
262
263 if (Ptr->RefCount <= 0)
264 return;
265
266 --Ptr->RefCount;
267 if (Ptr->RefCount == 0)
268 {
269 DPRINT("Releasing SharedMem for %p (%i, %p)\n", Ptr->Buffer, Ptr->IsMapping, Ptr);
270 if (Ptr->IsMapping)
271 MmUnmapViewInSystemSpace(Ptr->Buffer);
272 else
273 ExFreePoolWithTag(Ptr->Buffer, TAG_FONT);
274 ExFreePoolWithTag(Ptr, TAG_FONT);
275 }
276 }
277
278 static void
279 SharedFaceCache_Release(PSHARED_FACE_CACHE Cache)
280 {
281 RtlFreeUnicodeString(&Cache->FontFamily);
282 RtlFreeUnicodeString(&Cache->FullName);
283 }
284
285 static void
286 SharedFace_Release(PSHARED_FACE Ptr)
287 {
288 IntLockFreeType;
289 ASSERT(Ptr->RefCount > 0);
290
291 if (Ptr->RefCount <= 0)
292 return;
293
294 --Ptr->RefCount;
295 if (Ptr->RefCount == 0)
296 {
297 DPRINT("Releasing SharedFace for %s\n", Ptr->Face->family_name);
298 RemoveCacheEntries(Ptr->Face);
299 FT_Done_Face(Ptr->Face);
300 SharedMem_Release(Ptr->Memory);
301 SharedFaceCache_Release(&Ptr->EnglishUS);
302 SharedFaceCache_Release(&Ptr->UserLanguage);
303 ExFreePoolWithTag(Ptr, TAG_FONT);
304 }
305 IntUnLockFreeType;
306 }
307
308
309 /*
310 * IntLoadFontSubstList --- loads the list of font substitutes
311 */
312 BOOL FASTCALL
313 IntLoadFontSubstList(PLIST_ENTRY pHead)
314 {
315 NTSTATUS Status;
316 HANDLE KeyHandle;
317 OBJECT_ATTRIBUTES ObjectAttributes;
318 KEY_FULL_INFORMATION KeyFullInfo;
319 ULONG i, Length;
320 UNICODE_STRING FromW, ToW;
321 BYTE InfoBuffer[128];
322 PKEY_VALUE_FULL_INFORMATION pInfo;
323 BYTE CharSets[FONTSUBST_FROM_AND_TO];
324 LPWSTR pch;
325 PFONTSUBST_ENTRY pEntry;
326
327 /* the FontSubstitutes registry key */
328 static UNICODE_STRING FontSubstKey =
329 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\"
330 L"Microsoft\\Windows NT\\CurrentVersion\\"
331 L"FontSubstitutes");
332
333 /* open registry key */
334 InitializeObjectAttributes(&ObjectAttributes, &FontSubstKey,
335 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
336 NULL, NULL);
337 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
338 if (!NT_SUCCESS(Status))
339 {
340 DPRINT("ZwOpenKey failed: 0x%08X\n", Status);
341 return FALSE; /* failure */
342 }
343
344 /* query count of values */
345 Status = ZwQueryKey(KeyHandle, KeyFullInformation,
346 &KeyFullInfo, sizeof(KeyFullInfo), &Length);
347 if (!NT_SUCCESS(Status))
348 {
349 DPRINT("ZwQueryKey failed: 0x%08X\n", Status);
350 ZwClose(KeyHandle);
351 return FALSE; /* failure */
352 }
353
354 /* for each value */
355 for (i = 0; i < KeyFullInfo.Values; ++i)
356 {
357 /* get value name */
358 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
359 InfoBuffer, sizeof(InfoBuffer), &Length);
360 if (!NT_SUCCESS(Status))
361 {
362 DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status);
363 break; /* failure */
364 }
365
366 /* create FromW string */
367 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
368 Length = pInfo->NameLength / sizeof(WCHAR);
369 pInfo->Name[Length] = UNICODE_NULL; /* truncate */
370 Status = RtlCreateUnicodeString(&FromW, pInfo->Name);
371 if (!NT_SUCCESS(Status))
372 {
373 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
374 break; /* failure */
375 }
376
377 /* query value */
378 Status = ZwQueryValueKey(KeyHandle, &FromW, KeyValueFullInformation,
379 InfoBuffer, sizeof(InfoBuffer), &Length);
380 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
381 if (!NT_SUCCESS(Status) || !pInfo->DataLength)
382 {
383 DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status);
384 RtlFreeUnicodeString(&FromW);
385 break; /* failure */
386 }
387
388 /* create ToW string */
389 pch = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
390 Length = pInfo->DataLength / sizeof(WCHAR);
391 pch[Length] = UNICODE_NULL; /* truncate */
392 Status = RtlCreateUnicodeString(&ToW, pch);
393 if (!NT_SUCCESS(Status))
394 {
395 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
396 RtlFreeUnicodeString(&FromW);
397 break; /* failure */
398 }
399
400 /* does charset exist? (from) */
401 CharSets[FONTSUBST_FROM] = DEFAULT_CHARSET;
402 pch = wcsrchr(FromW.Buffer, L',');
403 if (pch)
404 {
405 /* truncate */
406 *pch = UNICODE_NULL;
407 FromW.Length = (pch - FromW.Buffer) * sizeof(WCHAR);
408 /* parse charset number */
409 CharSets[FONTSUBST_FROM] = (BYTE)_wtoi(pch + 1);
410 }
411
412 /* does charset exist? (to) */
413 CharSets[FONTSUBST_TO] = DEFAULT_CHARSET;
414 pch = wcsrchr(ToW.Buffer, L',');
415 if (pch)
416 {
417 /* truncate */
418 *pch = UNICODE_NULL;
419 ToW.Length = (pch - ToW.Buffer) * sizeof(WCHAR);
420 /* parse charset number */
421 CharSets[FONTSUBST_TO] = (BYTE)_wtoi(pch + 1);
422 }
423
424 /* allocate an entry */
425 pEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONTSUBST_ENTRY), TAG_FONT);
426 if (pEntry == NULL)
427 {
428 DPRINT("ExAllocatePoolWithTag failed\n");
429 RtlFreeUnicodeString(&FromW);
430 RtlFreeUnicodeString(&ToW);
431 break; /* failure */
432 }
433
434 /* store to *pEntry */
435 pEntry->FontNames[FONTSUBST_FROM] = FromW;
436 pEntry->FontNames[FONTSUBST_TO] = ToW;
437 pEntry->CharSets[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
438 pEntry->CharSets[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
439
440 /* insert pEntry to *pHead */
441 InsertTailList(pHead, &pEntry->ListEntry);
442 }
443
444 /* close now */
445 ZwClose(KeyHandle);
446
447 return NT_SUCCESS(Status);
448 }
449
450 BOOL FASTCALL
451 InitFontSupport(VOID)
452 {
453 ULONG ulError;
454
455 InitializeListHead(&FontListHead);
456 InitializeListHead(&FontCacheListHead);
457 FontCacheNumEntries = 0;
458 /* Fast Mutexes must be allocated from non paged pool */
459 FontListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
460 if (FontListLock == NULL)
461 {
462 return FALSE;
463 }
464
465 ExInitializeFastMutex(FontListLock);
466 FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
467 if (FreeTypeLock == NULL)
468 {
469 return FALSE;
470 }
471 ExInitializeFastMutex(FreeTypeLock);
472
473 ulError = FT_Init_FreeType(&library);
474 if (ulError)
475 {
476 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
477 return FALSE;
478 }
479
480 IntLoadSystemFonts();
481 IntLoadFontSubstList(&FontSubstListHead);
482
483 return TRUE;
484 }
485
486 VOID
487 FtSetCoordinateTransform(
488 FT_Face face,
489 PMATRIX pmx)
490 {
491 FT_Matrix ftmatrix;
492 FLOATOBJ efTemp;
493
494 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
495 efTemp = pmx->efM11;
496 FLOATOBJ_MulLong(&efTemp, 0x00010000);
497 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
498
499 efTemp = pmx->efM12;
500 FLOATOBJ_MulLong(&efTemp, 0x00010000);
501 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
502
503 efTemp = pmx->efM21;
504 FLOATOBJ_MulLong(&efTemp, 0x00010000);
505 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
506
507 efTemp = pmx->efM22;
508 FLOATOBJ_MulLong(&efTemp, 0x00010000);
509 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
510
511 /* Set the transformation matrix */
512 FT_Set_Transform(face, &ftmatrix, 0);
513 }
514
515 static BOOL
516 SubstituteFontByList(PLIST_ENTRY pHead,
517 PUNICODE_STRING pOutputName,
518 PUNICODE_STRING pInputName,
519 BYTE RequestedCharSet,
520 BYTE CharSetMap[FONTSUBST_FROM_AND_TO])
521 {
522 PLIST_ENTRY pListEntry;
523 PFONTSUBST_ENTRY pSubstEntry;
524 BYTE CharSets[FONTSUBST_FROM_AND_TO];
525
526 CharSetMap[FONTSUBST_FROM] = DEFAULT_CHARSET;
527 CharSetMap[FONTSUBST_TO] = RequestedCharSet;
528
529 /* for each list entry */
530 for (pListEntry = pHead->Flink;
531 pListEntry != pHead;
532 pListEntry = pListEntry->Flink)
533 {
534 pSubstEntry =
535 (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_ENTRY, ListEntry);
536
537 CharSets[FONTSUBST_FROM] = pSubstEntry->CharSets[FONTSUBST_FROM];
538
539 if (CharSets[FONTSUBST_FROM] != DEFAULT_CHARSET &&
540 CharSets[FONTSUBST_FROM] != RequestedCharSet)
541 {
542 continue; /* not matched */
543 }
544
545 /* does charset number exist? (to) */
546 if (pSubstEntry->CharSets[FONTSUBST_TO] != DEFAULT_CHARSET)
547 {
548 CharSets[FONTSUBST_TO] = pSubstEntry->CharSets[FONTSUBST_TO];
549 }
550 else
551 {
552 CharSets[FONTSUBST_TO] = RequestedCharSet;
553 }
554
555 /* does font name match? */
556 if (!RtlEqualUnicodeString(&pSubstEntry->FontNames[FONTSUBST_FROM],
557 pInputName, TRUE))
558 {
559 continue; /* not matched */
560 }
561
562 /* update *pOutputName */
563 *pOutputName = pSubstEntry->FontNames[FONTSUBST_TO];
564
565 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
566 {
567 /* update CharSetMap */
568 CharSetMap[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
569 CharSetMap[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
570 }
571 return TRUE; /* success */
572 }
573
574 return FALSE;
575 }
576
577 static BOOL
578 SubstituteFontRecurse(LOGFONTW* pLogFont)
579 {
580 UINT RecurseCount = 5;
581 UNICODE_STRING OutputNameW = { 0 };
582 BYTE CharSetMap[FONTSUBST_FROM_AND_TO];
583 BOOL Found;
584 UNICODE_STRING InputNameW;
585
586 if (pLogFont->lfFaceName[0] == UNICODE_NULL)
587 return FALSE;
588
589 RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
590
591 while (RecurseCount-- > 0)
592 {
593 Found = SubstituteFontByList(&FontSubstListHead,
594 &OutputNameW, &InputNameW,
595 pLogFont->lfCharSet, CharSetMap);
596 if (!Found)
597 break;
598
599 RtlStringCchCopyW(pLogFont->lfFaceName, LF_FACESIZE, OutputNameW.Buffer);
600
601 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
602 CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
603 {
604 pLogFont->lfCharSet = CharSetMap[FONTSUBST_TO];
605 }
606 }
607
608 return TRUE; /* success */
609 }
610
611 /*
612 * IntLoadSystemFonts
613 *
614 * Search the system font directory and adds each font found.
615 */
616 VOID FASTCALL
617 IntLoadSystemFonts(VOID)
618 {
619 OBJECT_ATTRIBUTES ObjectAttributes;
620 UNICODE_STRING Directory, FileName, TempString;
621 IO_STATUS_BLOCK Iosb;
622 HANDLE hDirectory;
623 BYTE *DirInfoBuffer;
624 PFILE_DIRECTORY_INFORMATION DirInfo;
625 BOOLEAN bRestartScan = TRUE;
626 NTSTATUS Status;
627 INT i;
628 static UNICODE_STRING SearchPatterns[] =
629 {
630 RTL_CONSTANT_STRING(L"*.ttf"),
631 RTL_CONSTANT_STRING(L"*.ttc"),
632 RTL_CONSTANT_STRING(L"*.otf"),
633 RTL_CONSTANT_STRING(L"*.otc"),
634 RTL_CONSTANT_STRING(L"*.fon"),
635 RTL_CONSTANT_STRING(L"*.fnt")
636 };
637
638 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
639
640 InitializeObjectAttributes(
641 &ObjectAttributes,
642 &Directory,
643 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
644 NULL,
645 NULL);
646
647 Status = ZwOpenFile(
648 &hDirectory,
649 SYNCHRONIZE | FILE_LIST_DIRECTORY,
650 &ObjectAttributes,
651 &Iosb,
652 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
653 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
654
655 if (NT_SUCCESS(Status))
656 {
657 for (i = 0; i < _countof(SearchPatterns); ++i)
658 {
659 DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
660 if (DirInfoBuffer == NULL)
661 {
662 ZwClose(hDirectory);
663 return;
664 }
665
666 FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
667 if (FileName.Buffer == NULL)
668 {
669 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
670 ZwClose(hDirectory);
671 return;
672 }
673 FileName.Length = 0;
674 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
675
676 while (1)
677 {
678 Status = ZwQueryDirectoryFile(
679 hDirectory,
680 NULL,
681 NULL,
682 NULL,
683 &Iosb,
684 DirInfoBuffer,
685 0x4000,
686 FileDirectoryInformation,
687 FALSE,
688 &SearchPatterns[i],
689 bRestartScan);
690
691 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
692 {
693 break;
694 }
695
696 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
697 while (1)
698 {
699 TempString.Buffer = DirInfo->FileName;
700 TempString.Length =
701 TempString.MaximumLength = DirInfo->FileNameLength;
702 RtlCopyUnicodeString(&FileName, &Directory);
703 RtlAppendUnicodeStringToString(&FileName, &TempString);
704 IntGdiAddFontResource(&FileName, 0);
705 if (DirInfo->NextEntryOffset == 0)
706 break;
707 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
708 }
709
710 bRestartScan = FALSE;
711 }
712
713 ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
714 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
715 }
716 ZwClose(hDirectory);
717 }
718 }
719
720 static BYTE
721 ItalicFromStyle(const char *style_name)
722 {
723 if (style_name == NULL || style_name[0] == 0)
724 return FALSE;
725 if (strstr(style_name, "Italic") != NULL)
726 return TRUE;
727 if (strstr(style_name, "Oblique") != NULL)
728 return TRUE;
729 return FALSE;
730 }
731
732 static LONG
733 WeightFromStyle(const char *style_name)
734 {
735 if (style_name == NULL || style_name[0] == 0)
736 return FW_NORMAL;
737 if (strstr(style_name, "Regular") != NULL)
738 return FW_REGULAR;
739 if (strstr(style_name, "Normal") != NULL)
740 return FW_NORMAL;
741 if (strstr(style_name, "SemiBold") != NULL)
742 return FW_SEMIBOLD;
743 if (strstr(style_name, "UltraBold") != NULL)
744 return FW_ULTRABOLD;
745 if (strstr(style_name, "DemiBold") != NULL)
746 return FW_DEMIBOLD;
747 if (strstr(style_name, "ExtraBold") != NULL)
748 return FW_EXTRABOLD;
749 if (strstr(style_name, "Bold") != NULL)
750 return FW_BOLD;
751 if (strstr(style_name, "UltraLight") != NULL)
752 return FW_ULTRALIGHT;
753 if (strstr(style_name, "ExtraLight") != NULL)
754 return FW_EXTRALIGHT;
755 if (strstr(style_name, "Light") != NULL)
756 return FW_LIGHT;
757 if (strstr(style_name, "Hairline") != NULL)
758 return 50;
759 if (strstr(style_name, "Book") != NULL)
760 return 350;
761 if (strstr(style_name, "ExtraBlack") != NULL)
762 return 950;
763 if (strstr(style_name, "UltraBlack") != NULL)
764 return 1000;
765 if (strstr(style_name, "Black") != NULL)
766 return FW_BLACK;
767 if (strstr(style_name, "Medium") != NULL)
768 return FW_MEDIUM;
769 if (strstr(style_name, "Thin") != NULL)
770 return FW_THIN;
771 if (strstr(style_name, "Heavy") != NULL)
772 return FW_HEAVY;
773 return FW_NORMAL;
774 }
775
776 static INT FASTCALL
777 IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
778 PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
779 {
780 FT_Error Error;
781 PFONT_ENTRY Entry;
782 FONT_ENTRY_MEM* PrivateEntry = NULL;
783 FONTGDI * FontGDI;
784 NTSTATUS Status;
785 FT_Face Face;
786 ANSI_STRING AnsiFaceName;
787 FT_WinFNT_HeaderRec WinFNT;
788 INT FaceCount = 0, CharSetCount = 0;
789 PUNICODE_STRING pFileName = pLoadFont->pFileName;
790 DWORD Characteristics = pLoadFont->Characteristics;
791 PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
792 TT_OS2 * pOS2;
793 INT BitIndex;
794 FT_UShort os2_version;
795 FT_ULong os2_ulCodePageRange1;
796 FT_UShort os2_usWeightClass;
797
798 if (SharedFace == NULL && CharSetIndex == -1)
799 {
800 /* load a face from memory */
801 IntLockFreeType;
802 Error = FT_New_Memory_Face(
803 library,
804 pLoadFont->Memory->Buffer,
805 pLoadFont->Memory->BufferSize,
806 ((FontIndex != -1) ? FontIndex : 0),
807 &Face);
808
809 if (!Error)
810 SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
811
812 IntUnLockFreeType;
813
814 if (!Error && FT_IS_SFNT(Face))
815 pLoadFont->IsTrueType = TRUE;
816
817 if (Error || SharedFace == NULL)
818 {
819 if (SharedFace)
820 SharedFace_Release(SharedFace);
821
822 if (Error == FT_Err_Unknown_File_Format)
823 DPRINT1("Unknown font file format\n");
824 else
825 DPRINT1("Error reading font (error code: %d)\n", Error);
826 return 0; /* failure */
827 }
828 }
829 else
830 {
831 Face = SharedFace->Face;
832 IntLockFreeType;
833 SharedFace_AddRef(SharedFace);
834 IntUnLockFreeType;
835 }
836
837 /* allocate a FONT_ENTRY */
838 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
839 if (!Entry)
840 {
841 SharedFace_Release(SharedFace);
842 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
843 return 0; /* failure */
844 }
845
846 /* allocate a FONTGDI */
847 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
848 if (!FontGDI)
849 {
850 SharedFace_Release(SharedFace);
851 ExFreePoolWithTag(Entry, TAG_FONT);
852 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
853 return 0; /* failure */
854 }
855
856 /* set file name */
857 if (pFileName)
858 {
859 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool,
860 pFileName->Length + sizeof(UNICODE_NULL),
861 GDITAG_PFF);
862 if (FontGDI->Filename == NULL)
863 {
864 EngFreeMem(FontGDI);
865 SharedFace_Release(SharedFace);
866 ExFreePoolWithTag(Entry, TAG_FONT);
867 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
868 return 0; /* failure */
869 }
870 RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
871 FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
872 }
873 else
874 {
875 FontGDI->Filename = NULL;
876
877 PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT);
878 if (!PrivateEntry)
879 {
880 if (FontGDI->Filename)
881 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
882 EngFreeMem(FontGDI);
883 SharedFace_Release(SharedFace);
884 ExFreePoolWithTag(Entry, TAG_FONT);
885 return 0;
886 }
887
888 PrivateEntry->Entry = Entry;
889 if (pLoadFont->PrivateEntry)
890 {
891 InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry);
892 }
893 else
894 {
895 InitializeListHead(&PrivateEntry->ListEntry);
896 pLoadFont->PrivateEntry = PrivateEntry;
897 }
898 }
899
900 /* set face */
901 FontGDI->SharedFace = SharedFace;
902 FontGDI->CharSet = ANSI_CHARSET;
903 FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name);
904 FontGDI->RequestItalic = FALSE;
905 FontGDI->OriginalWeight = WeightFromStyle(Face->style_name);
906 FontGDI->RequestWeight = FW_NORMAL;
907
908 RtlInitAnsiString(&AnsiFaceName, Face->family_name);
909 Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
910 if (!NT_SUCCESS(Status))
911 {
912 if (PrivateEntry)
913 {
914 if (pLoadFont->PrivateEntry == PrivateEntry)
915 {
916 pLoadFont->PrivateEntry = NULL;
917 }
918 else
919 {
920 RemoveEntryList(&PrivateEntry->ListEntry);
921 }
922 ExFreePoolWithTag(PrivateEntry, TAG_FONT);
923 }
924 if (FontGDI->Filename)
925 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
926 EngFreeMem(FontGDI);
927 SharedFace_Release(SharedFace);
928 ExFreePoolWithTag(Entry, TAG_FONT);
929 return 0;
930 }
931
932 os2_version = 0;
933 IntLockFreeType;
934 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
935 if (pOS2)
936 {
937 os2_version = pOS2->version;
938 os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
939 os2_usWeightClass = pOS2->usWeightClass;
940 }
941 IntUnLockFreeType;
942
943 if (pOS2 && os2_version >= 1)
944 {
945 /* get charset and weight from OS/2 header */
946
947 /* Make sure we do not use this pointer anymore */
948 pOS2 = NULL;
949
950 for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
951 {
952 if (os2_ulCodePageRange1 & (1 << BitIndex))
953 {
954 if (FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
955 continue;
956
957 if ((CharSetIndex == -1 && CharSetCount == 0) ||
958 CharSetIndex == CharSetCount)
959 {
960 FontGDI->CharSet = FontTci[BitIndex].ciCharset;
961 }
962
963 ++CharSetCount;
964 }
965 }
966
967 /* set actual weight */
968 FontGDI->OriginalWeight = os2_usWeightClass;
969 }
970 else
971 {
972 /* get charset from WinFNT header */
973 IntLockFreeType;
974 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
975 if (!Error)
976 {
977 FontGDI->CharSet = WinFNT.charset;
978 }
979 IntUnLockFreeType;
980 }
981
982 /* FIXME: CharSet is invalid on Marlett */
983 if (RtlEqualUnicodeString(&Entry->FaceName, &MarlettW, TRUE))
984 {
985 FontGDI->CharSet = SYMBOL_CHARSET;
986 }
987
988 ++FaceCount;
989 DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
990 DPRINT("Num glyphs: %d\n", Face->num_glyphs);
991 DPRINT("CharSet: %d\n", FontGDI->CharSet);
992
993 /* Add this font resource to the font table */
994 Entry->Font = FontGDI;
995 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
996
997 if (Characteristics & FR_PRIVATE)
998 {
999 /* private font */
1000 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1001 IntLockProcessPrivateFonts(Win32Process);
1002 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
1003 IntUnLockProcessPrivateFonts(Win32Process);
1004 }
1005 else
1006 {
1007 /* global font */
1008 IntLockGlobalFonts;
1009 InsertTailList(&FontListHead, &Entry->ListEntry);
1010 IntUnLockGlobalFonts;
1011 }
1012
1013 if (FontIndex == -1)
1014 {
1015 if (FT_IS_SFNT(Face))
1016 {
1017 TT_Face TrueType = (TT_Face)Face;
1018 if (TrueType->ttc_header.count > 1)
1019 {
1020 FT_Long i;
1021 for (i = 1; i < TrueType->ttc_header.count; ++i)
1022 {
1023 FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
1024 }
1025 }
1026 }
1027 FontIndex = 0;
1028 }
1029
1030 if (CharSetIndex == -1)
1031 {
1032 INT i;
1033
1034 if (pLoadFont->RegValueName.Length == 0)
1035 {
1036 RtlCreateUnicodeString(pValueName, Entry->FaceName.Buffer);
1037 }
1038 else
1039 {
1040 UNICODE_STRING NewString;
1041 USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + Entry->FaceName.Length;
1042 NewString.Length = 0;
1043 NewString.MaximumLength = Length + sizeof(WCHAR);
1044 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1045 NewString.MaximumLength,
1046 TAG_USTR);
1047 NewString.Buffer[0] = UNICODE_NULL;
1048
1049 RtlAppendUnicodeStringToString(&NewString, pValueName);
1050 RtlAppendUnicodeToString(&NewString, L" & ");
1051 RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
1052
1053 RtlFreeUnicodeString(pValueName);
1054 *pValueName = NewString;
1055 }
1056
1057 for (i = 1; i < CharSetCount; ++i)
1058 {
1059 /* Do not count charsets towards 'faces' loaded */
1060 IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
1061 }
1062 }
1063
1064 return FaceCount; /* number of loaded faces */
1065 }
1066
1067 /*
1068 * IntGdiAddFontResource
1069 *
1070 * Adds the font resource from the specified file to the system.
1071 */
1072
1073 INT FASTCALL
1074 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
1075 {
1076 NTSTATUS Status;
1077 HANDLE FileHandle;
1078 PVOID Buffer = NULL;
1079 IO_STATUS_BLOCK Iosb;
1080 PVOID SectionObject;
1081 ULONG ViewSize = 0;
1082 LARGE_INTEGER SectionSize;
1083 OBJECT_ATTRIBUTES ObjectAttributes;
1084 GDI_LOAD_FONT LoadFont;
1085 INT FontCount;
1086 HANDLE KeyHandle;
1087 static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
1088
1089 /* Open the font file */
1090 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
1091 Status = ZwOpenFile(
1092 &FileHandle,
1093 FILE_GENERIC_READ | SYNCHRONIZE,
1094 &ObjectAttributes,
1095 &Iosb,
1096 FILE_SHARE_READ,
1097 FILE_SYNCHRONOUS_IO_NONALERT);
1098 if (!NT_SUCCESS(Status))
1099 {
1100 DPRINT("Could not load font file: %wZ\n", FileName);
1101 return 0;
1102 }
1103
1104 SectionSize.QuadPart = 0LL;
1105 Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
1106 NULL, &SectionSize, PAGE_READONLY,
1107 SEC_COMMIT, FileHandle, NULL);
1108 if (!NT_SUCCESS(Status))
1109 {
1110 DPRINT("Could not map file: %wZ\n", FileName);
1111 ZwClose(FileHandle);
1112 return 0;
1113 }
1114 ZwClose(FileHandle);
1115
1116 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
1117 if (!NT_SUCCESS(Status))
1118 {
1119 DPRINT("Could not map file: %wZ\n", FileName);
1120 ObDereferenceObject(SectionObject);
1121 return 0;
1122 }
1123
1124 LoadFont.pFileName = FileName;
1125 LoadFont.Memory = SharedMem_Create(Buffer, ViewSize, TRUE);
1126 LoadFont.Characteristics = Characteristics;
1127 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1128 LoadFont.IsTrueType = FALSE;
1129 LoadFont.PrivateEntry = NULL;
1130 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1131
1132 ObDereferenceObject(SectionObject);
1133
1134 /* Release our copy */
1135 IntLockFreeType;
1136 SharedMem_Release(LoadFont.Memory);
1137 IntUnLockFreeType;
1138
1139 if (FontCount > 0)
1140 {
1141 if (LoadFont.IsTrueType)
1142 {
1143 /* append " (TrueType)" */
1144 UNICODE_STRING NewString;
1145 USHORT Length;
1146
1147 Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length;
1148 NewString.Length = 0;
1149 NewString.MaximumLength = Length + sizeof(WCHAR);
1150 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1151 NewString.MaximumLength,
1152 TAG_USTR);
1153 NewString.Buffer[0] = UNICODE_NULL;
1154
1155 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
1156 RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
1157 RtlFreeUnicodeString(&LoadFont.RegValueName);
1158 LoadFont.RegValueName = NewString;
1159 }
1160
1161 /* registry */
1162 InitializeObjectAttributes(&ObjectAttributes, &FontRegPath,
1163 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1164 NULL, NULL);
1165 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
1166 if (NT_SUCCESS(Status))
1167 {
1168 ULONG DataSize;
1169 LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
1170 if (pFileName)
1171 {
1172 pFileName++;
1173 DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
1174 ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
1175 pFileName, DataSize);
1176 }
1177 ZwClose(KeyHandle);
1178 }
1179 }
1180 RtlFreeUnicodeString(&LoadFont.RegValueName);
1181
1182 return FontCount;
1183 }
1184
1185 HANDLE FASTCALL
1186 IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
1187 {
1188 GDI_LOAD_FONT LoadFont;
1189 FONT_ENTRY_COLL_MEM* EntryCollection;
1190 INT FaceCount;
1191 HANDLE Ret = 0;
1192
1193 PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
1194
1195 if (!BufferCopy)
1196 {
1197 *pNumAdded = 0;
1198 return NULL;
1199 }
1200 memcpy(BufferCopy, Buffer, dwSize);
1201
1202 LoadFont.pFileName = NULL;
1203 LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
1204 LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
1205 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1206 LoadFont.IsTrueType = FALSE;
1207 LoadFont.PrivateEntry = NULL;
1208 FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1209
1210 RtlFreeUnicodeString(&LoadFont.RegValueName);
1211
1212 /* Release our copy */
1213 IntLockFreeType;
1214 SharedMem_Release(LoadFont.Memory);
1215 IntUnLockFreeType;
1216
1217 if (FaceCount > 0)
1218 {
1219 EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
1220 if (EntryCollection)
1221 {
1222 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1223 EntryCollection->Entry = LoadFont.PrivateEntry;
1224 IntLockProcessPrivateFonts(Win32Process);
1225 EntryCollection->Handle = ++Win32Process->PrivateMemFontHandleCount;
1226 InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
1227 IntUnLockProcessPrivateFonts(Win32Process);
1228 Ret = (HANDLE)EntryCollection->Handle;
1229 }
1230 }
1231 *pNumAdded = FaceCount;
1232
1233 return Ret;
1234 }
1235
1236 // FIXME: Add RemoveFontResource
1237
1238 static VOID FASTCALL
1239 CleanupFontEntry(PFONT_ENTRY FontEntry)
1240 {
1241 PFONTGDI FontGDI = FontEntry->Font;
1242 PSHARED_FACE SharedFace = FontGDI->SharedFace;
1243
1244 if (FontGDI->Filename)
1245 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1246
1247 EngFreeMem(FontGDI);
1248 SharedFace_Release(SharedFace);
1249 ExFreePoolWithTag(FontEntry, TAG_FONT);
1250 }
1251
1252 VOID FASTCALL
1253 IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
1254 {
1255 PLIST_ENTRY Entry;
1256 PFONT_ENTRY_MEM FontEntry;
1257
1258 while (!IsListEmpty(&Head->ListEntry))
1259 {
1260 Entry = RemoveHeadList(&Head->ListEntry);
1261 FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
1262
1263 CleanupFontEntry(FontEntry->Entry);
1264 ExFreePoolWithTag(FontEntry, TAG_FONT);
1265 }
1266
1267 CleanupFontEntry(Head->Entry);
1268 ExFreePoolWithTag(Head, TAG_FONT);
1269 }
1270
1271 static VOID FASTCALL
1272 UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)
1273 {
1274 PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
1275 PLIST_ENTRY ListEntry;
1276 RemoveEntryList(&Collection->ListEntry);
1277
1278 do {
1279 /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
1280 RemoveEntryList(&FontMemEntry->Entry->ListEntry);
1281
1282 ListEntry = FontMemEntry->ListEntry.Flink;
1283 FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
1284
1285 } while (FontMemEntry != Collection->Entry);
1286 }
1287
1288 BOOL FASTCALL
1289 IntGdiRemoveFontMemResource(HANDLE hMMFont)
1290 {
1291 PLIST_ENTRY Entry;
1292 PFONT_ENTRY_COLL_MEM CurrentEntry;
1293 PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
1294 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1295
1296 IntLockProcessPrivateFonts(Win32Process);
1297 Entry = Win32Process->PrivateMemFontListHead.Flink;
1298 while (Entry != &Win32Process->PrivateMemFontListHead)
1299 {
1300 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1301
1302 if (CurrentEntry->Handle == (UINT)hMMFont)
1303 {
1304 EntryCollection = CurrentEntry;
1305 UnlinkFontMemCollection(CurrentEntry);
1306 break;
1307 }
1308
1309 Entry = Entry->Flink;
1310 }
1311 IntUnLockProcessPrivateFonts(Win32Process);
1312
1313 if (EntryCollection)
1314 {
1315 IntGdiCleanupMemEntry(EntryCollection->Entry);
1316 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1317 return TRUE;
1318 }
1319 return FALSE;
1320 }
1321
1322
1323 VOID FASTCALL
1324 IntGdiCleanupPrivateFontsForProcess(VOID)
1325 {
1326 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1327 PLIST_ENTRY Entry;
1328 PFONT_ENTRY_COLL_MEM EntryCollection;
1329
1330 DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
1331 do {
1332 Entry = NULL;
1333 EntryCollection = NULL;
1334
1335 IntLockProcessPrivateFonts(Win32Process);
1336 if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
1337 {
1338 Entry = Win32Process->PrivateMemFontListHead.Flink;
1339 EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1340 UnlinkFontMemCollection(EntryCollection);
1341 }
1342 IntUnLockProcessPrivateFonts(Win32Process);
1343
1344 if (EntryCollection)
1345 {
1346 IntGdiCleanupMemEntry(EntryCollection->Entry);
1347 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1348 }
1349 else
1350 {
1351 /* No Mem fonts anymore, see if we have any other private fonts left */
1352 Entry = NULL;
1353 IntLockProcessPrivateFonts(Win32Process);
1354 if (!IsListEmpty(&Win32Process->PrivateFontListHead))
1355 {
1356 Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
1357 }
1358 IntUnLockProcessPrivateFonts(Win32Process);
1359
1360 if (Entry)
1361 {
1362 CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
1363 }
1364 }
1365
1366 } while (Entry);
1367 }
1368
1369 BOOL FASTCALL
1370 IntIsFontRenderingEnabled(VOID)
1371 {
1372 BOOL Ret = RenderingEnabled;
1373 HDC hDC;
1374
1375 hDC = IntGetScreenDC();
1376 if (hDC)
1377 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
1378
1379 return Ret;
1380 }
1381
1382 VOID FASTCALL
1383 IntEnableFontRendering(BOOL Enable)
1384 {
1385 RenderingEnabled = Enable;
1386 }
1387
1388 FT_Render_Mode FASTCALL
1389 IntGetFontRenderMode(LOGFONTW *logfont)
1390 {
1391 switch (logfont->lfQuality)
1392 {
1393 case ANTIALIASED_QUALITY:
1394 break;
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 FT_Render_Mode RenderMode,
2612 PMATRIX pmx)
2613 {
2614 PLIST_ENTRY CurrentEntry;
2615 PFONT_CACHE_ENTRY FontEntry;
2616
2617 ASSERT_FREETYPE_LOCK_HELD();
2618
2619 CurrentEntry = FontCacheListHead.Flink;
2620 while (CurrentEntry != &FontCacheListHead)
2621 {
2622 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
2623 if ((FontEntry->Face == Face) &&
2624 (FontEntry->GlyphIndex == GlyphIndex) &&
2625 (FontEntry->Height == Height) &&
2626 (FontEntry->RenderMode == RenderMode) &&
2627 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2628 break;
2629 CurrentEntry = CurrentEntry->Flink;
2630 }
2631
2632 if (CurrentEntry == &FontCacheListHead)
2633 {
2634 return NULL;
2635 }
2636
2637 RemoveEntryList(CurrentEntry);
2638 InsertHeadList(&FontCacheListHead, CurrentEntry);
2639 return FontEntry->BitmapGlyph;
2640 }
2641
2642 /* no cache */
2643 FT_BitmapGlyph APIENTRY
2644 ftGdiGlyphSet(
2645 FT_Face Face,
2646 FT_GlyphSlot GlyphSlot,
2647 FT_Render_Mode RenderMode)
2648 {
2649 FT_Glyph Glyph;
2650 INT error;
2651 FT_Bitmap AlignedBitmap;
2652 FT_BitmapGlyph BitmapGlyph;
2653
2654 error = FT_Get_Glyph(GlyphSlot, &Glyph);
2655 if (error)
2656 {
2657 DPRINT1("Failure getting glyph.\n");
2658 return NULL;
2659 }
2660
2661 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2662 if (error)
2663 {
2664 FT_Done_Glyph(Glyph);
2665 DPRINT1("Failure rendering glyph.\n");
2666 return NULL;
2667 }
2668
2669 BitmapGlyph = (FT_BitmapGlyph)Glyph;
2670 FT_Bitmap_New(&AlignedBitmap);
2671 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2672 {
2673 DPRINT1("Conversion failed\n");
2674 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2675 return NULL;
2676 }
2677
2678 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2679 BitmapGlyph->bitmap = AlignedBitmap;
2680
2681 return BitmapGlyph;
2682 }
2683
2684 FT_BitmapGlyph APIENTRY
2685 ftGdiGlyphCacheSet(
2686 FT_Face Face,
2687 INT GlyphIndex,
2688 INT Height,
2689 PMATRIX pmx,
2690 FT_GlyphSlot GlyphSlot,
2691 FT_Render_Mode RenderMode)
2692 {
2693 FT_Glyph GlyphCopy;
2694 INT error;
2695 PFONT_CACHE_ENTRY NewEntry;
2696 FT_Bitmap AlignedBitmap;
2697 FT_BitmapGlyph BitmapGlyph;
2698
2699 ASSERT_FREETYPE_LOCK_HELD();
2700
2701 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2702 if (error)
2703 {
2704 DPRINT1("Failure caching glyph.\n");
2705 return NULL;
2706 };
2707
2708 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2709 if (error)
2710 {
2711 FT_Done_Glyph(GlyphCopy);
2712 DPRINT1("Failure rendering glyph.\n");
2713 return NULL;
2714 };
2715
2716 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
2717 if (!NewEntry)
2718 {
2719 DPRINT1("Alloc failure caching glyph.\n");
2720 FT_Done_Glyph(GlyphCopy);
2721 return NULL;
2722 }
2723
2724 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2725 FT_Bitmap_New(&AlignedBitmap);
2726 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2727 {
2728 DPRINT1("Conversion failed\n");
2729 ExFreePoolWithTag(NewEntry, TAG_FONT);
2730 FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
2731 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2732 return NULL;
2733 }
2734
2735 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2736 BitmapGlyph->bitmap = AlignedBitmap;
2737
2738 NewEntry->GlyphIndex = GlyphIndex;
2739 NewEntry->Face = Face;
2740 NewEntry->BitmapGlyph = BitmapGlyph;
2741 NewEntry->Height = Height;
2742 NewEntry->RenderMode = RenderMode;
2743 NewEntry->mxWorldToDevice = *pmx;
2744
2745 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
2746 if (++FontCacheNumEntries > MAX_FONT_CACHE)
2747 {
2748 NewEntry = CONTAINING_RECORD(FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
2749 RemoveCachedEntry(NewEntry);
2750 }
2751
2752 return BitmapGlyph;
2753 }
2754
2755
2756 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2757 {
2758 pt->x.value = vec->x >> 6;
2759 pt->x.fract = (vec->x & 0x3f) << 10;
2760 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2761 pt->y.value = vec->y >> 6;
2762 pt->y.fract = (vec->y & 0x3f) << 10;
2763 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2764 }
2765
2766 /*
2767 This function builds an FT_Fixed from a float. It puts the integer part
2768 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2769 It fails if the integer part of the float number is greater than SHORT_MAX.
2770 */
2771 static __inline FT_Fixed FT_FixedFromFloat(float f)
2772 {
2773 short value = f;
2774 unsigned short fract = (f - value) * 0xFFFF;
2775 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2776 }
2777
2778 /*
2779 This function builds an FT_Fixed from a FIXED. It simply put f.value
2780 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2781 */
2782 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2783 {
2784 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2785 }
2786
2787 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2788 {
2789 TTPOLYGONHEADER *pph;
2790 TTPOLYCURVE *ppc;
2791 int needed = 0, point = 0, contour, first_pt;
2792 unsigned int pph_start, cpfx;
2793 DWORD type;
2794
2795 for (contour = 0; contour < outline->n_contours; contour++)
2796 {
2797 /* Ignore contours containing one point */
2798 if (point == outline->contours[contour])
2799 {
2800 point++;
2801 continue;
2802 }
2803
2804 pph_start = needed;
2805 pph = (TTPOLYGONHEADER *)(buf + needed);
2806 first_pt = point;
2807 if (buf)
2808 {
2809 pph->dwType = TT_POLYGON_TYPE;
2810 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2811 }
2812 needed += sizeof(*pph);
2813 point++;
2814 while (point <= outline->contours[contour])
2815 {
2816 ppc = (TTPOLYCURVE *)(buf + needed);
2817 type = outline->tags[point] & FT_Curve_Tag_On ?
2818 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2819 cpfx = 0;
2820 do
2821 {
2822 if (buf)
2823 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2824 cpfx++;
2825 point++;
2826 } while (point <= outline->contours[contour] &&
2827 (outline->tags[point] & FT_Curve_Tag_On) ==
2828 (outline->tags[point-1] & FT_Curve_Tag_On));
2829 /* At the end of a contour Windows adds the start point, but
2830 only for Beziers */
2831 if (point > outline->contours[contour] &&
2832 !(outline->tags[point-1] & FT_Curve_Tag_On))
2833 {
2834 if (buf)
2835 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2836 cpfx++;
2837 }
2838 else if (point <= outline->contours[contour] &&
2839 outline->tags[point] & FT_Curve_Tag_On)
2840 {
2841 /* add closing pt for bezier */
2842 if (buf)
2843 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2844 cpfx++;
2845 point++;
2846 }
2847 if (buf)
2848 {
2849 ppc->wType = type;
2850 ppc->cpfx = cpfx;
2851 }
2852 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2853 }
2854 if (buf)
2855 pph->cb = needed - pph_start;
2856 }
2857 return needed;
2858 }
2859
2860 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2861 {
2862 /* Convert the quadratic Beziers to cubic Beziers.
2863 The parametric eqn for a cubic Bezier is, from PLRM:
2864 r(t) = at^3 + bt^2 + ct + r0
2865 with the control points:
2866 r1 = r0 + c/3
2867 r2 = r1 + (c + b)/3
2868 r3 = r0 + c + b + a
2869
2870 A quadratic Bezier has the form:
2871 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2872
2873 So equating powers of t leads to:
2874 r1 = 2/3 p1 + 1/3 p0
2875 r2 = 2/3 p1 + 1/3 p2
2876 and of course r0 = p0, r3 = p2
2877 */
2878 int contour, point = 0, first_pt;
2879 TTPOLYGONHEADER *pph;
2880 TTPOLYCURVE *ppc;
2881 DWORD pph_start, cpfx, type;
2882 FT_Vector cubic_control[4];
2883 unsigned int needed = 0;
2884
2885 for (contour = 0; contour < outline->n_contours; contour++)
2886 {
2887 pph_start = needed;
2888 pph = (TTPOLYGONHEADER *)(buf + needed);
2889 first_pt = point;
2890 if (buf)
2891 {
2892 pph->dwType = TT_POLYGON_TYPE;
2893 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2894 }
2895 needed += sizeof(*pph);
2896 point++;
2897 while (point <= outline->contours[contour])
2898 {
2899 ppc = (TTPOLYCURVE *)(buf + needed);
2900 type = outline->tags[point] & FT_Curve_Tag_On ?
2901 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2902 cpfx = 0;
2903 do
2904 {
2905 if (type == TT_PRIM_LINE)
2906 {
2907 if (buf)
2908 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2909 cpfx++;
2910 point++;
2911 }
2912 else
2913 {
2914 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2915 so cpfx = 3n */
2916
2917 /* FIXME: Possible optimization in endpoint calculation
2918 if there are two consecutive curves */
2919 cubic_control[0] = outline->points[point-1];
2920 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2921 {
2922 cubic_control[0].x += outline->points[point].x + 1;
2923 cubic_control[0].y += outline->points[point].y + 1;
2924 cubic_control[0].x >>= 1;
2925 cubic_control[0].y >>= 1;
2926 }
2927 if (point+1 > outline->contours[contour])
2928 cubic_control[3] = outline->points[first_pt];
2929 else
2930 {
2931 cubic_control[3] = outline->points[point+1];
2932 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2933 {
2934 cubic_control[3].x += outline->points[point].x + 1;
2935 cubic_control[3].y += outline->points[point].y + 1;
2936 cubic_control[3].x >>= 1;
2937 cubic_control[3].y >>= 1;
2938 }
2939 }
2940 /* r1 = 1/3 p0 + 2/3 p1
2941 r2 = 1/3 p2 + 2/3 p1 */
2942 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2943 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2944 cubic_control[2] = cubic_control[1];
2945 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2946 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2947 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2948 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2949 if (buf)
2950 {
2951 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2952 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2953 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2954 }
2955 cpfx += 3;
2956 point++;
2957 }
2958 } while (point <= outline->contours[contour] &&
2959 (outline->tags[point] & FT_Curve_Tag_On) ==
2960 (outline->tags[point-1] & FT_Curve_Tag_On));
2961 /* At the end of a contour Windows adds the start point,
2962 but only for Beziers and we've already done that.
2963 */
2964 if (point <= outline->contours[contour] &&
2965 outline->tags[point] & FT_Curve_Tag_On)
2966 {
2967 /* This is the closing pt of a bezier, but we've already
2968 added it, so just inc point and carry on */
2969 point++;
2970 }
2971 if (buf)
2972 {
2973 ppc->wType = type;
2974 ppc->cpfx = cpfx;
2975 }
2976 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2977 }
2978 if (buf)
2979 pph->cb = needed - pph_start;
2980 }
2981 return needed;
2982 }
2983
2984 static INT
2985 IntRequestFontSize(PDC dc, FT_Face face, LONG Width, LONG Height)
2986 {
2987 FT_Size_RequestRec req;
2988
2989 if (Width < 0)
2990 Width = -Width;
2991
2992 if (Height < 0)
2993 {
2994 Height = -Height;
2995 }
2996 if (Height == 0)
2997 {
2998 Height = dc->ppdev->devinfo.lfDefaultFont.lfHeight;
2999 }
3000 if (Height == 0)
3001 {
3002 Height = Width;
3003 }
3004
3005 if (Height < 1)
3006 Height = 1;
3007
3008 if (Width > 0xFFFFU)
3009 Width = 0xFFFFU;
3010 if (Height > 0xFFFFU)
3011 Height = 0xFFFFU;
3012
3013 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
3014 req.width = (FT_Long)(Width << 6);
3015 req.height = (FT_Long)(Height << 6);
3016 req.horiResolution = 0;
3017 req.vertResolution = 0;
3018 return FT_Request_Size(face, &req);
3019 }
3020
3021 BOOL
3022 FASTCALL
3023 TextIntUpdateSize(PDC dc,
3024 PTEXTOBJ TextObj,
3025 PFONTGDI FontGDI,
3026 BOOL bDoLock)
3027 {
3028 FT_Face face;
3029 INT error, n;
3030 FT_CharMap charmap, found;
3031 LOGFONTW *plf;
3032
3033 if (bDoLock)
3034 IntLockFreeType;
3035
3036 face = FontGDI->SharedFace->Face;
3037 if (face->charmap == NULL)
3038 {
3039 DPRINT("WARNING: No charmap selected!\n");
3040 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3041
3042 found = NULL;
3043 for (n = 0; n < face->num_charmaps; n++)
3044 {
3045 charmap = face->charmaps[n];
3046 DPRINT("Found charmap encoding: %i\n", charmap->encoding);
3047 if (charmap->encoding != 0)
3048 {
3049 found = charmap;
3050 break;
3051 }
3052 }
3053 if (!found)
3054 {
3055 DPRINT1("WARNING: Could not find desired charmap!\n");
3056 }
3057 else
3058 {
3059 error = FT_Set_Charmap(face, found);
3060 if (error)
3061 {
3062 DPRINT1("WARNING: Could not set the charmap!\n");
3063 }
3064 }
3065 }
3066
3067 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3068
3069 error = IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
3070
3071 if (bDoLock)
3072 IntUnLockFreeType;
3073
3074 if (error)
3075 {
3076 DPRINT1("Error in setting pixel sizes: %d\n", error);
3077 return FALSE;
3078 }
3079
3080 return TRUE;
3081 }
3082
3083
3084 /*
3085 * Based on WineEngGetGlyphOutline
3086 *
3087 */
3088 ULONG
3089 FASTCALL
3090 ftGdiGetGlyphOutline(
3091 PDC dc,
3092 WCHAR wch,
3093 UINT iFormat,
3094 LPGLYPHMETRICS pgm,
3095 ULONG cjBuf,
3096 PVOID pvBuf,
3097 LPMAT2 pmat2,
3098 BOOL bIgnoreRotation)
3099 {
3100 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3101 PDC_ATTR pdcattr;
3102 PTEXTOBJ TextObj;
3103 PFONTGDI FontGDI;
3104 HFONT hFont = 0;
3105 GLYPHMETRICS gm;
3106 ULONG Size;
3107 FT_Face ft_face;
3108 FT_UInt glyph_index;
3109 DWORD width, height, pitch, needed = 0;
3110 FT_Bitmap ft_bitmap;
3111 FT_Error error;
3112 INT left, right, top = 0, bottom = 0;
3113 FT_Angle angle = 0;
3114 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3115 FLOAT eM11, widthRatio = 1.0;
3116 FT_Matrix transMat = identityMat;
3117 BOOL needsTransform = FALSE;
3118 INT orientation;
3119 LONG aveWidth;
3120 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3121 OUTLINETEXTMETRICW *potm;
3122 XFORM xForm;
3123 LOGFONTW *plf;
3124
3125 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3126 cjBuf, pvBuf, pmat2);
3127
3128 pdcattr = dc->pdcattr;
3129
3130 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
3131 eM11 = xForm.eM11;
3132
3133 hFont = pdcattr->hlfntNew;
3134 TextObj = RealizeFontInit(hFont);
3135
3136 if (!TextObj)
3137 {
3138 EngSetLastError(ERROR_INVALID_HANDLE);
3139 return GDI_ERROR;
3140 }
3141 FontGDI = ObjToGDI(TextObj->Font, FONT);
3142 ft_face = FontGDI->SharedFace->Face;
3143
3144 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3145 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3146 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3147
3148 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3149 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3150 if (!potm)
3151 {
3152 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3153 TEXTOBJ_UnlockText(TextObj);
3154 return GDI_ERROR;
3155 }
3156 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
3157 if (!Size)
3158 {
3159 /* FIXME: last error? */
3160 ExFreePoolWithTag(potm, GDITAG_TEXT);
3161 TEXTOBJ_UnlockText(TextObj);
3162 return GDI_ERROR;
3163 }
3164
3165 IntLockFreeType;
3166 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3167 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
3168
3169 TEXTOBJ_UnlockText(TextObj);
3170
3171 if (iFormat & GGO_GLYPH_INDEX)
3172 {
3173 glyph_index = wch;
3174 iFormat &= ~GGO_GLYPH_INDEX;
3175 }
3176 else glyph_index = FT_Get_Char_Index(ft_face, wch);
3177
3178 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3179 load_flags |= FT_LOAD_NO_BITMAP;
3180
3181 if (iFormat & GGO_UNHINTED)
3182 {
3183 load_flags |= FT_LOAD_NO_HINTING;
3184 iFormat &= ~GGO_UNHINTED;
3185 }
3186
3187 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3188 if (error)
3189 {
3190 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3191 IntUnLockFreeType;
3192 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3193 return GDI_ERROR;
3194 }
3195 IntUnLockFreeType;
3196
3197 if (aveWidth && potm)
3198 {
3199 widthRatio = (FLOAT)aveWidth * eM11 /
3200 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
3201 }
3202
3203 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3204 right = (INT)((ft_face->glyph->metrics.horiBearingX +
3205 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3206
3207 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3208 lsb = left >> 6;
3209 bbx = (right - left) >> 6;
3210
3211 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3212
3213 IntLockFreeType;
3214
3215 /* Scaling transform */
3216 /*if (aveWidth)*/
3217 {
3218
3219 FT_Matrix ftmatrix;
3220 FLOATOBJ efTemp;
3221
3222 PMATRIX pmx = DC_pmxWorldToDevice(dc);
3223
3224 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3225 efTemp = pmx->efM11;
3226 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3227 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
3228
3229 efTemp = pmx->efM12;
3230 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3231 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
3232
3233 efTemp = pmx->efM21;
3234 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3235 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
3236
3237 efTemp = pmx->efM22;
3238 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3239 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
3240
3241 FT_Matrix_Multiply(&ftmatrix, &transMat);
3242 needsTransform = TRUE;
3243 }
3244
3245 /* Rotation transform */
3246 if (orientation)
3247 {
3248 FT_Matrix rotationMat;
3249 FT_Vector vecAngle;
3250 DPRINT("Rotation Trans!\n");
3251 angle = FT_FixedFromFloat((float)orientation / 10.0);
3252 FT_Vector_Unit(&vecAngle, angle);
3253 rotationMat.xx = vecAngle.x;
3254 rotationMat.xy = -vecAngle.y;
3255 rotationMat.yx = -rotationMat.xy;
3256 rotationMat.yy = rotationMat.xx;
3257 FT_Matrix_Multiply(&rotationMat, &transMat);
3258 needsTransform = TRUE;
3259 }
3260
3261 /* Extra transformation specified by caller */
3262 if (pmat2)
3263 {
3264 FT_Matrix extraMat;
3265 DPRINT("MAT2 Matrix Trans!\n");
3266 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
3267 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
3268 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
3269 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
3270 FT_Matrix_Multiply(&extraMat, &transMat);
3271 needsTransform = TRUE;
3272 }
3273
3274 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
3275
3276 if (!needsTransform)
3277 {
3278 DPRINT("No Need to be Transformed!\n");
3279 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3280 bottom = (ft_face->glyph->metrics.horiBearingY -
3281 ft_face->glyph->metrics.height) & -64;
3282 gm.gmCellIncX = adv;
3283 gm.gmCellIncY = 0;
3284 }
3285 else
3286 {
3287 INT xc, yc;
3288 FT_Vector vec;
3289 for (xc = 0; xc < 2; xc++)
3290 {
3291 for (yc = 0; yc < 2; yc++)
3292 {
3293 vec.x = (ft_face->glyph->metrics.horiBearingX +
3294 xc * ft_face->glyph->metrics.width);
3295 vec.y = ft_face->glyph->metrics.horiBearingY -
3296 yc * ft_face->glyph->metrics.height;
3297 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
3298 FT_Vector_Transform(&vec, &transMat);
3299 if (xc == 0 && yc == 0)
3300 {
3301 left = right = vec.x;
3302 top = bottom = vec.y;
3303 }
3304 else
3305 {
3306 if (vec.x < left) left = vec.x;
3307 else if (vec.x > right) right = vec.x;
3308 if (vec.y < bottom) bottom = vec.y;
3309 else if (vec.y > top) top = vec.y;
3310 }
3311 }
3312 }
3313 left = left & -64;
3314 right = (right + 63) & -64;
3315 bottom = bottom & -64;
3316 top = (top + 63) & -64;
3317
3318 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3319 vec.x = ft_face->glyph->metrics.horiAdvance;
3320 vec.y = 0;
3321 FT_Vector_Transform(&vec, &transMat);
3322 gm.gmCellIncX = (vec.x+63) >> 6;
3323 gm.gmCellIncY = -((vec.y+63) >> 6);
3324 }
3325 gm.gmBlackBoxX = (right - left) >> 6;
3326 gm.gmBlackBoxY = (top - bottom) >> 6;
3327 gm.gmptGlyphOrigin.x = left >> 6;
3328 gm.gmptGlyphOrigin.y = top >> 6;
3329
3330 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
3331 gm.gmCellIncX, gm.gmCellIncY,
3332 gm.gmBlackBoxX, gm.gmBlackBoxY,
3333 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
3334
3335 IntUnLockFreeType;
3336
3337
3338 if (iFormat == GGO_METRICS)
3339 {
3340 DPRINT("GGO_METRICS Exit!\n");
3341 *pgm = gm;
3342 return 1; /* FIXME */
3343 }
3344
3345 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
3346 {
3347 DPRINT1("Loaded a bitmap\n");
3348 return GDI_ERROR;
3349 }
3350
3351 switch (iFormat)
3352 {
3353 case GGO_BITMAP:
3354 width = gm.gmBlackBoxX;
3355 height = gm.gmBlackBoxY;
3356 pitch = ((width + 31) >> 5) << 2;
3357 needed = pitch * height;
3358
3359 if (!pvBuf || !cjBuf) break;
3360 if (!needed) return GDI_ERROR; /* empty glyph */
3361 if (needed > cjBuf)
3362 return GDI_ERROR;
3363
3364 switch (ft_face->glyph->format)
3365 {
3366 case ft_glyph_format_bitmap:
3367 {
3368 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3369 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
3370 INT h = min( height, ft_face->glyph->bitmap.rows );
3371 while (h--)
3372 {
3373 RtlCopyMemory(dst, src, w);
3374 src += ft_face->glyph->bitmap.pitch;
3375 dst += pitch;
3376 }
3377 break;
3378 }
3379
3380 case ft_glyph_format_outline:
3381 ft_bitmap.width = width;
3382 ft_bitmap.rows = height;
3383 ft_bitmap.pitch = pitch;
3384 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
3385 ft_bitmap.buffer = pvBuf;
3386
3387 IntLockFreeType;
3388 if (needsTransform)
3389 {
3390 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3391 }
3392 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3393 /* Note: FreeType will only set 'black' bits for us. */
3394 RtlZeroMemory(pvBuf, needed);
3395 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3396 IntUnLockFreeType;
3397 break;
3398
3399 default:
3400 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3401 return GDI_ERROR;
3402 }
3403 break;
3404
3405 case GGO_GRAY2_BITMAP:
3406 case GGO_GRAY4_BITMAP:
3407 case GGO_GRAY8_BITMAP:
3408 {
3409 unsigned int mult, row, col;
3410 BYTE *start, *ptr;
3411
3412 width = gm.gmBlackBoxX;
3413 height = gm.gmBlackBoxY;
3414 pitch = (width + 3) / 4 * 4;
3415 needed = pitch * height;
3416
3417 if (!pvBuf || !cjBuf) break;
3418 if (!needed) return GDI_ERROR; /* empty glyph */
3419 if (needed > cjBuf)
3420 return GDI_ERROR;
3421
3422 switch (ft_face->glyph->format)
3423 {
3424 case ft_glyph_format_bitmap:
3425 {
3426 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3427 INT h = min( height, ft_face->glyph->bitmap.rows );
3428 INT x;
3429 while (h--)
3430 {
3431 for (x = 0; (UINT)x < pitch; x++)
3432 {
3433 if (x < ft_face->glyph->bitmap.width)
3434 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3435 else
3436 dst[x] = 0;
3437 }
3438 src += ft_face->glyph->bitmap.pitch;
3439 dst += pitch;
3440 }
3441 break;
3442 }
3443 case ft_glyph_format_outline:
3444 {
3445 ft_bitmap.width = width;
3446 ft_bitmap.rows = height;
3447 ft_bitmap.pitch = pitch;
3448 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3449 ft_bitmap.buffer = pvBuf;
3450
3451 IntLockFreeType;
3452 if (needsTransform)
3453 {
3454 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3455 }
3456 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3457 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
3458 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3459 IntUnLockFreeType;
3460
3461 if (iFormat == GGO_GRAY2_BITMAP)
3462 mult = 4;
3463 else if (iFormat == GGO_GRAY4_BITMAP)
3464 mult = 16;
3465 else if (iFormat == GGO_GRAY8_BITMAP)
3466 mult = 64;
3467 else
3468 {
3469 return GDI_ERROR;
3470 }
3471
3472 start = pvBuf;
3473 for (row = 0; row < height; row++)
3474 {
3475 ptr = start;
3476 for (col = 0; col < width; col++, ptr++)
3477 {
3478 *ptr = (((int)*ptr) * mult + 128) / 256;
3479 }
3480 start += pitch;
3481 }
3482
3483 break;
3484 }
3485 default:
3486 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3487 return GDI_ERROR;
3488 }
3489 }
3490
3491 case GGO_NATIVE:
3492 {
3493 FT_Outline *outline = &ft_face->glyph->outline;
3494
3495 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
3496
3497 IntLockFreeType;
3498 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
3499
3500 needed = get_native_glyph_outline(outline, cjBuf, NULL);
3501
3502 if (!pvBuf || !cjBuf)
3503 {
3504 IntUnLockFreeType;
3505 break;
3506 }
3507 if (needed > cjBuf)
3508 {
3509 IntUnLockFreeType;
3510 return GDI_ERROR;
3511 }
3512 get_native_glyph_outline(outline, cjBuf, pvBuf);
3513 IntUnLockFreeType;
3514 break;
3515 }
3516 case GGO_BEZIER:
3517 {
3518 FT_Outline *outline = &ft_face->glyph->outline;
3519 if (cjBuf == 0) pvBuf = NULL;
3520
3521 if (needsTransform && pvBuf)
3522 {
3523 IntLockFreeType;
3524 FT_Outline_Transform(outline, &transMat);
3525 IntUnLockFreeType;
3526 }
3527 needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
3528
3529 if (!pvBuf || !cjBuf)
3530 break;
3531 if (needed > cjBuf)
3532 return GDI_ERROR;
3533
3534 get_bezier_glyph_outline(outline, cjBuf, pvBuf);
3535 break;
3536 }
3537
3538 default:
3539 DPRINT1("Unsupported format %u\n", iFormat);
3540 return GDI_ERROR;
3541 }
3542
3543 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
3544 *pgm = gm;
3545 return needed;
3546 }
3547
3548 BOOL
3549 FASTCALL
3550 TextIntGetTextExtentPoint(PDC dc,
3551 PTEXTOBJ TextObj,
3552 LPCWSTR String,
3553 INT Count,
3554 ULONG MaxExtent,
3555 LPINT Fit,
3556 LPINT Dx,
3557 LPSIZE Size,
3558 FLONG fl)
3559 {
3560 PFONTGDI FontGDI;
3561 FT_Face face;
3562 FT_GlyphSlot glyph;
3563 FT_BitmapGlyph realglyph;
3564 INT error, glyph_index, i, previous;
3565 ULONGLONG TotalWidth = 0;
3566 BOOL use_kerning;
3567 FT_Render_Mode RenderMode;
3568 BOOLEAN Render;
3569 PMATRIX pmxWorldToDevice;
3570 LOGFONTW *plf;
3571 BOOL EmuBold, EmuItalic;
3572 LONG ascender, descender;
3573
3574 FontGDI = ObjToGDI(TextObj->Font, FONT);
3575
3576 face = FontGDI->SharedFace->Face;
3577 if (NULL != Fit)
3578 {
3579 *Fit = 0;
3580 }
3581
3582 IntLockFreeType;
3583
3584 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3585
3586 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3587 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
3588 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
3589
3590 Render = IntIsFontRenderingEnabled();
3591 if (Render)
3592 RenderMode = IntGetFontRenderMode(plf);
3593 else
3594 RenderMode = FT_RENDER_MODE_MONO;
3595
3596 /* Get the DC's world-to-device transformation matrix */
3597 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3598 FtSetCoordinateTransform(face, pmxWorldToDevice);
3599
3600 use_kerning = FT_HAS_KERNING(face);
3601 previous = 0;
3602
3603 for (i = 0; i < Count; i++)
3604 {
3605 if (fl & GTEF_INDICES)
3606 glyph_index = *String;
3607 else
3608 glyph_index = FT_Get_Char_Index(face, *String);
3609
3610 if (EmuBold || EmuItalic)
3611 realglyph = NULL;
3612 else
3613 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
3614 RenderMode, pmxWorldToDevice);
3615
3616 if (EmuBold || EmuItalic || !realglyph)
3617 {
3618 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3619 if (error)
3620 {
3621 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
3622 break;
3623 }
3624
3625 glyph = face->glyph;
3626 if (EmuBold || EmuItalic)
3627 {
3628 if (EmuBold)
3629 FT_GlyphSlot_Embolden(glyph);
3630 if (EmuItalic)
3631 FT_GlyphSlot_Oblique(glyph);
3632 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
3633 }
3634 else
3635 {
3636 realglyph = ftGdiGlyphCacheSet(face,
3637 glyph_index,
3638 plf->lfHeight,
3639 pmxWorldToDevice,
3640 glyph,
3641 RenderMode);
3642 }
3643
3644 if (!realglyph)
3645 {
3646 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3647 break;
3648 }
3649 }
3650
3651 /* Retrieve kerning distance */
3652 if (use_kerning && previous && glyph_index)
3653 {
3654 FT_Vector delta;
3655 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3656 TotalWidth += delta.x;
3657 }
3658
3659 TotalWidth += realglyph->root.advance.x >> 10;
3660
3661 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
3662 {
3663 *Fit = i + 1;
3664 }
3665 if (NULL != Dx)
3666 {
3667 Dx[i] = (TotalWidth + 32) >> 6;
3668 }
3669
3670 if (EmuBold || EmuItalic)
3671 {
3672 FT_Done_Glyph((FT_Glyph)realglyph);
3673 realglyph = NULL;
3674 }
3675
3676 previous = glyph_index;
3677 String++;
3678 }
3679 ascender = (face->size->metrics.ascender + 32) >> 6; /* Units above baseline */
3680 descender = (32 - face->size->metrics.descender) >> 6; /* Units below baseline */
3681 IntUnLockFreeType;
3682
3683 Size->cx = (TotalWidth + 32) >> 6;
3684 Size->cy = ascender + descender;
3685
3686 return TRUE;
3687 }
3688
3689
3690 INT
3691 FASTCALL
3692 ftGdiGetTextCharsetInfo(
3693 PDC Dc,
3694 LPFONTSIGNATURE lpSig,
3695 DWORD dwFlags)
3696 {
3697 PDC_ATTR pdcattr;
3698 UINT Ret = DEFAULT_CHARSET;
3699 INT i;
3700 HFONT hFont;
3701 PTEXTOBJ TextObj;
3702 PFONTGDI FontGdi;
3703 FONTSIGNATURE fs;
3704 TT_OS2 *pOS2;
3705 FT_Face Face;
3706 CHARSETINFO csi;
3707 DWORD cp, fs0;
3708 USHORT usACP, usOEM;
3709
3710 pdcattr = Dc->pdcattr;
3711 hFont = pdcattr->hlfntNew;
3712 TextObj = RealizeFontInit(hFont);
3713
3714 if (!TextObj)
3715 {
3716 EngSetLastError(ERROR_INVALID_HANDLE);
3717 return Ret;
3718 }
3719 FontGdi = ObjToGDI(TextObj->Font, FONT);
3720 Face = FontGdi->SharedFace->Face;
3721 TEXTOBJ_UnlockText(TextObj);
3722
3723 IntLockFreeType;
3724 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3725 IntUnLockFreeType;
3726 memset(&fs, 0, sizeof(FONTSIGNATURE