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