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