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