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