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