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