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