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