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