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