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