ReactOS  0.4.12-dev-90-g2e2e63e
freetype.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS win32 kernel mode subsystem
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: win32ss/gdi/ntgdi/freetype.c
5  * PURPOSE: FreeType font engine interface
6  * PROGRAMMERS: Copyright 2001 Huw D M Davies for CodeWeavers.
7  * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
8  * Copyright 2016-2018 Katayama Hirofumi MZ.
9  */
10 
13 #include <win32k.h>
14 
15 #include FT_GLYPH_H
16 #include FT_TYPE1_TABLES_H
17 #include FT_TRUETYPE_TABLES_H
18 #include FT_TRUETYPE_TAGS_H
19 #include FT_TRIGONOMETRY_H
20 #include FT_BITMAP_H
21 #include FT_OUTLINE_H
22 #include FT_WINFONTS_H
23 #include FT_SFNT_NAMES_H
24 #include FT_SYNTHESIS_H
25 #include FT_TRUETYPE_IDS_H
26 
27 #ifndef FT_INTERNAL_INTERNAL_H
28  #define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h>
29  #include FT_INTERNAL_INTERNAL_H
30 #endif
31 #include FT_INTERNAL_TRUETYPE_TYPES_H
32 
33 #include <gdi/eng/floatobj.h>
34 #include "font.h"
35 
36 #define NDEBUG
37 #include <debug.h>
38 
39 /* TPMF_FIXED_PITCH is confusing; brain-dead api */
40 #ifndef _TMPF_VARIABLE_PITCH
41  #define _TMPF_VARIABLE_PITCH TMPF_FIXED_PITCH
42 #endif
43 
44 extern const MATRIX gmxWorldToDeviceDefault;
45 extern const MATRIX gmxWorldToPageDefault;
46 
47 /* HACK!! Fix XFORMOBJ then use 1:16 / 16:1 */
48 #define gmxWorldToDeviceDefault gmxWorldToPageDefault
49 
51 
52 /* special font names */
54 
55 /* registry */
57  RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
58 
59 
60 /* The FreeType library is not thread safe, so we have
61  to serialize access to it */
63 
67 
68 #define IntLockGlobalFonts() \
69  ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FontListLock)
70 
71 #define IntUnLockGlobalFonts() \
72  ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FontListLock)
73 
74 #define ASSERT_GLOBALFONTS_LOCK_HELD() \
75  ASSERT(g_FontListLock->Owner == KeGetCurrentThread())
76 
77 #define IntLockFreeType() \
78  ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FreeTypeLock)
79 
80 #define IntUnLockFreeType() \
81  ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FreeTypeLock)
82 
83 #define ASSERT_FREETYPE_LOCK_HELD() \
84  ASSERT(g_FreeTypeLock->Owner == KeGetCurrentThread())
85 
86 #define ASSERT_FREETYPE_LOCK_NOT_HELD() \
87  ASSERT(g_FreeTypeLock->Owner != KeGetCurrentThread())
88 
89 #define MAX_FONT_CACHE 256
90 
93 
94 static PWCHAR g_ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */
95 {
96  L"Western", /* 00 */
97  L"Central_European",
98  L"Cyrillic",
99  L"Greek",
100  L"Turkish",
101  L"Hebrew",
102  L"Arabic",
103  L"Baltic",
104  L"Vietnamese", /* 08 */
105  NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */
106  L"Thai",
107  L"Japanese",
108  L"CHINESE_GB2312",
109  L"Hangul",
110  L"CHINESE_BIG5",
111  L"Hangul(Johab)",
112  NULL, NULL, /* 23 */
113  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
114  L"Symbol" /* 31 */
115 };
116 
117 /*
118  * For TranslateCharsetInfo
119  */
120 #define CP_SYMBOL 42
121 #define MAXTCIINDEX 32
123 {
124  /* ANSI */
125  { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
126  { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
127  { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
128  { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
129  { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
130  { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
131  { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
132  { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
133  { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
134  /* reserved by ANSI */
135  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
136  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
137  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
138  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
139  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
140  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
141  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
142  /* ANSI and OEM */
143  { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
144  { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
145  { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
146  { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
147  { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
148  { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
149  /* Reserved for alternate ANSI and OEM */
150  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
151  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
152  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
153  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
154  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
155  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
157  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
158  /* Reserved for system */
159  { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
160  { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
161 };
162 
163 #ifndef CP_OEMCP
164  #define CP_OEMCP 1
165  #define CP_MACCP 2
166 #endif
167 
168 /* Get charset from specified codepage.
169  g_FontTci is used also in TranslateCharsetInfo. */
171 {
172  UINT i;
173 
174  if (uCodePage == CP_OEMCP)
175  return OEM_CHARSET;
176 
177  if (uCodePage == CP_MACCP)
178  return MAC_CHARSET;
179 
180  for (i = 0; i < MAXTCIINDEX; ++i)
181  {
182  if (g_FontTci[i].ciACP == 0)
183  continue;
184 
185  if (g_FontTci[i].ciACP == uCodePage)
186  return g_FontTci[i].ciCharset;
187  }
188 
189  return DEFAULT_CHARSET;
190 }
191 
192 /* list head */
193 static RTL_STATIC_LIST_HEAD(g_FontSubstListHead);
194 
195 static void
197 {
199 
200  ++Ptr->RefCount;
201 }
202 
203 static void
205 {
206  Cache->OutlineRequiredSize = 0;
209 }
210 
211 static PSHARED_FACE
213 {
216  if (Ptr)
217  {
218  Ptr->Face = Face;
219  Ptr->RefCount = 1;
220  Ptr->Memory = Memory;
223 
224  SharedMem_AddRef(Memory);
225  DPRINT("Creating SharedFace for %s\n", Face->family_name ? Face->family_name : "<NULL>");
226  }
227  return Ptr;
228 }
229 
230 static PSHARED_MEM
232 {
235  if (Ptr)
236  {
237  Ptr->Buffer = Buffer;
238  Ptr->BufferSize = BufferSize;
239  Ptr->RefCount = 1;
240  Ptr->IsMapping = IsMapping;
241  DPRINT("Creating SharedMem for %p (%i, %p)\n", Buffer, IsMapping, Ptr);
242  }
243  return Ptr;
244 }
245 
246 static void
248 {
250 
251  ++Ptr->RefCount;
252 }
253 
254 static void
256 {
258 
260  RemoveEntryList(&Entry->ListEntry);
261  ExFreePoolWithTag(Entry, TAG_FONT);
264 }
265 
266 static void
268 {
269  PLIST_ENTRY CurrentEntry, NextEntry;
270  PFONT_CACHE_ENTRY FontEntry;
271 
273 
274  for (CurrentEntry = g_FontCacheListHead.Flink;
275  CurrentEntry != &g_FontCacheListHead;
276  CurrentEntry = NextEntry)
277  {
278  FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
279  NextEntry = CurrentEntry->Flink;
280 
281  if (FontEntry->Face == Face)
282  {
283  RemoveCachedEntry(FontEntry);
284  }
285  }
286 }
287 
289 {
291  ASSERT(Ptr->RefCount > 0);
292 
293  if (Ptr->RefCount <= 0)
294  return;
295 
296  --Ptr->RefCount;
297  if (Ptr->RefCount == 0)
298  {
299  DPRINT("Releasing SharedMem for %p (%i, %p)\n", Ptr->Buffer, Ptr->IsMapping, Ptr);
300  if (Ptr->IsMapping)
302  else
305  }
306 }
307 
308 static void
310 {
313 }
314 
315 static void
317 {
318  IntLockFreeType();
319  ASSERT(Ptr->RefCount > 0);
320 
321  if (Ptr->RefCount <= 0)
322  return;
323 
324  --Ptr->RefCount;
325  if (Ptr->RefCount == 0)
326  {
327  DPRINT("Releasing SharedFace for %s\n", Ptr->Face->family_name ? Ptr->Face->family_name : "<NULL>");
328  RemoveCacheEntries(Ptr->Face);
329  FT_Done_Face(Ptr->Face);
334  }
336 }
337 
338 #if DBG
339 VOID DumpFontGDI(PFONTGDI FontGDI)
340 {
341  const char *family_name;
342  const char *style_name;
343  FT_Face Face;
344 
345  if (!FontGDI)
346  {
347  DPRINT("FontGDI NULL\n");
348  return;
349  }
350 
351  Face = (FontGDI->SharedFace ? FontGDI->SharedFace->Face : NULL);
352  if (Face)
353  {
354  family_name = Face->family_name;
355  if (!family_name)
356  family_name = "<NULL>";
357 
358  style_name = Face->style_name;
359  if (!style_name)
360  style_name = "<NULL>";
361  }
362  else
363  {
364  family_name = "<invalid>";
365  style_name = "<invalid>";
366  }
367 
368  DPRINT("family_name '%s', style_name '%s', FontGDI %p, FontObj %p, iUnique %lu, SharedFace %p, Face %p, CharSet %u, Filename '%S'\n",
369  family_name,
370  style_name,
371  FontGDI,
372  FontGDI->FontObj,
373  FontGDI->iUnique,
374  FontGDI->SharedFace,
375  Face,
376  FontGDI->CharSet,
377  FontGDI->Filename);
378 }
379 
380 VOID DumpFontList(PLIST_ENTRY Head)
381 {
383  PFONT_ENTRY CurrentEntry;
384  PFONTGDI FontGDI;
385 
386  DPRINT("## DumpFontList(%p)\n", Head);
387 
388  for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
389  {
390  CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
391  FontGDI = CurrentEntry->Font;
392 
393  DumpFontGDI(FontGDI);
394  }
395 }
396 
397 VOID DumpFontSubstEntry(PFONTSUBST_ENTRY pSubstEntry)
398 {
399  DPRINT("%wZ,%u -> %wZ,%u\n",
400  &pSubstEntry->FontNames[FONTSUBST_FROM],
401  pSubstEntry->CharSets[FONTSUBST_FROM],
402  &pSubstEntry->FontNames[FONTSUBST_TO],
403  pSubstEntry->CharSets[FONTSUBST_TO]);
404 }
405 
406 VOID DumpFontSubstList(VOID)
407 {
408  PLIST_ENTRY pHead = &g_FontSubstListHead;
409  PLIST_ENTRY pListEntry;
410  PFONTSUBST_ENTRY pSubstEntry;
411 
412  DPRINT("## DumpFontSubstList\n");
413 
414  for (pListEntry = pHead->Flink;
415  pListEntry != pHead;
416  pListEntry = pListEntry->Flink)
417  {
418  pSubstEntry =
419  (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_ENTRY, ListEntry);
420 
421  DumpFontSubstEntry(pSubstEntry);
422  }
423 }
424 
425 VOID DumpPrivateFontList(BOOL bDoLock)
426 {
428 
429  if (!Win32Process)
430  return;
431 
432  if (bDoLock)
433  IntLockProcessPrivateFonts(Win32Process);
434 
435  DumpFontList(&Win32Process->PrivateFontListHead);
436 
437  if (bDoLock)
438  IntUnLockProcessPrivateFonts(Win32Process);
439 }
440 
441 VOID DumpGlobalFontList(BOOL bDoLock)
442 {
443  if (bDoLock)
445 
446  DumpFontList(&g_FontListHead);
447 
448  if (bDoLock)
450 }
451 
452 VOID DumpFontInfo(BOOL bDoLock)
453 {
454  DumpGlobalFontList(bDoLock);
455  DumpPrivateFontList(bDoLock);
456  DumpFontSubstList();
457 }
458 #endif
459 
460 /*
461  * IntLoadFontSubstList --- loads the list of font substitutes
462  */
465 {
469  KEY_FULL_INFORMATION KeyFullInfo;
470  ULONG i, Length;
471  UNICODE_STRING FromW, ToW;
472  BYTE InfoBuffer[128];
474  BYTE CharSets[FONTSUBST_FROM_AND_TO];
475  LPWSTR pch;
476  PFONTSUBST_ENTRY pEntry;
478 
479  /* the FontSubstitutes registry key */
480  static UNICODE_STRING FontSubstKey =
481  RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\"
482  L"Microsoft\\Windows NT\\CurrentVersion\\"
483  L"FontSubstitutes");
484 
485  /* open registry key */
486  InitializeObjectAttributes(&ObjectAttributes, &FontSubstKey,
488  NULL, NULL);
489  Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
490  if (!NT_SUCCESS(Status))
491  {
492  DPRINT("ZwOpenKey failed: 0x%08X\n", Status);
493  return FALSE; /* failure */
494  }
495 
496  /* query count of values */
497  Status = ZwQueryKey(KeyHandle, KeyFullInformation,
498  &KeyFullInfo, sizeof(KeyFullInfo), &Length);
499  if (!NT_SUCCESS(Status))
500  {
501  DPRINT("ZwQueryKey failed: 0x%08X\n", Status);
502  ZwClose(KeyHandle);
503  return FALSE; /* failure */
504  }
505 
506  /* for each value */
507  for (i = 0; i < KeyFullInfo.Values; ++i)
508  {
509  /* get value name */
510  Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
511  InfoBuffer, sizeof(InfoBuffer), &Length);
512  if (!NT_SUCCESS(Status))
513  {
514  DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status);
515  break; /* failure */
516  }
517 
518  /* create FromW string */
519  pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
520  Length = pInfo->NameLength / sizeof(WCHAR);
521  pInfo->Name[Length] = UNICODE_NULL; /* truncate */
522  Success = RtlCreateUnicodeString(&FromW, pInfo->Name);
523  if (!Success)
524  {
526  DPRINT("RtlCreateUnicodeString failed\n");
527  break; /* failure */
528  }
529 
530  /* query value */
531  Status = ZwQueryValueKey(KeyHandle, &FromW, KeyValueFullInformation,
532  InfoBuffer, sizeof(InfoBuffer), &Length);
533  pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
534  if (!NT_SUCCESS(Status) || !pInfo->DataLength)
535  {
536  DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status);
537  RtlFreeUnicodeString(&FromW);
538  break; /* failure */
539  }
540 
541  /* create ToW string */
542  pch = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
543  Length = pInfo->DataLength / sizeof(WCHAR);
544  pch[Length] = UNICODE_NULL; /* truncate */
545  Success = RtlCreateUnicodeString(&ToW, pch);
546  if (!Success)
547  {
549  DPRINT("RtlCreateUnicodeString failed\n");
550  RtlFreeUnicodeString(&FromW);
551  break; /* failure */
552  }
553 
554  /* does charset exist? (from) */
555  CharSets[FONTSUBST_FROM] = DEFAULT_CHARSET;
556  pch = wcsrchr(FromW.Buffer, L',');
557  if (pch)
558  {
559  /* truncate */
560  *pch = UNICODE_NULL;
561  FromW.Length = (pch - FromW.Buffer) * sizeof(WCHAR);
562  /* parse charset number */
563  CharSets[FONTSUBST_FROM] = (BYTE)_wtoi(pch + 1);
564  }
565 
566  /* does charset exist? (to) */
567  CharSets[FONTSUBST_TO] = DEFAULT_CHARSET;
568  pch = wcsrchr(ToW.Buffer, L',');
569  if (pch)
570  {
571  /* truncate */
572  *pch = UNICODE_NULL;
573  ToW.Length = (pch - ToW.Buffer) * sizeof(WCHAR);
574  /* parse charset number */
575  CharSets[FONTSUBST_TO] = (BYTE)_wtoi(pch + 1);
576  }
577 
578  /* is it identical? */
579  if (RtlEqualUnicodeString(&FromW, &ToW, TRUE) &&
580  CharSets[FONTSUBST_FROM] == CharSets[FONTSUBST_TO])
581  {
582  RtlFreeUnicodeString(&FromW);
583  RtlFreeUnicodeString(&ToW);
584  continue;
585  }
586 
587  /* allocate an entry */
589  if (pEntry == NULL)
590  {
591  DPRINT("ExAllocatePoolWithTag failed\n");
592  RtlFreeUnicodeString(&FromW);
593  RtlFreeUnicodeString(&ToW);
594  break; /* failure */
595  }
596 
597  /* store to *pEntry */
598  pEntry->FontNames[FONTSUBST_FROM] = FromW;
599  pEntry->FontNames[FONTSUBST_TO] = ToW;
600  pEntry->CharSets[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
601  pEntry->CharSets[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
602 
603  /* insert pEntry to *pHead */
604  InsertTailList(pHead, &pEntry->ListEntry);
605  }
606 
607  /* close now */
608  ZwClose(KeyHandle);
609 
610  return NT_SUCCESS(Status);
611 }
612 
615 {
616  ULONG ulError;
617 
618  InitializeListHead(&g_FontListHead);
619  InitializeListHead(&g_FontCacheListHead);
621  /* Fast Mutexes must be allocated from non paged pool */
623  if (g_FontListLock == NULL)
624  {
625  return FALSE;
626  }
627 
630  if (g_FreeTypeLock == NULL)
631  {
632  return FALSE;
633  }
635 
636  ulError = FT_Init_FreeType(&g_FreeTypeLibrary);
637  if (ulError)
638  {
639  DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
640  return FALSE;
641  }
642 
644  IntLoadFontSubstList(&g_FontSubstListHead);
645 
646 #if DBG
647  DumpFontInfo(TRUE);
648 #endif
649 
650  return TRUE;
651 }
652 
653 VOID
655  FT_Face face,
656  PMATRIX pmx)
657 {
658  FT_Matrix ftmatrix;
659  FLOATOBJ efTemp;
660 
661  /* Create a freetype matrix, by converting to 16.16 fixpoint format */
662  efTemp = pmx->efM11;
663  FLOATOBJ_MulLong(&efTemp, 0x00010000);
664  ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
665 
666  efTemp = pmx->efM12;
667  FLOATOBJ_MulLong(&efTemp, 0x00010000);
668  ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
669 
670  efTemp = pmx->efM21;
671  FLOATOBJ_MulLong(&efTemp, 0x00010000);
672  ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
673 
674  efTemp = pmx->efM22;
675  FLOATOBJ_MulLong(&efTemp, 0x00010000);
676  ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
677 
678  /* Set the transformation matrix */
679  FT_Set_Transform(face, &ftmatrix, 0);
680 }
681 
682 static BOOL
684  PUNICODE_STRING pOutputName,
685  PUNICODE_STRING pInputName,
686  BYTE RequestedCharSet,
687  BYTE CharSetMap[FONTSUBST_FROM_AND_TO])
688 {
689  PLIST_ENTRY pListEntry;
690  PFONTSUBST_ENTRY pSubstEntry;
691  BYTE CharSets[FONTSUBST_FROM_AND_TO];
692 
693  CharSetMap[FONTSUBST_FROM] = DEFAULT_CHARSET;
694  CharSetMap[FONTSUBST_TO] = RequestedCharSet;
695 
696  /* for each list entry */
697  for (pListEntry = pHead->Flink;
698  pListEntry != pHead;
699  pListEntry = pListEntry->Flink)
700  {
701  pSubstEntry =
702  (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_ENTRY, ListEntry);
703 
704  CharSets[FONTSUBST_FROM] = pSubstEntry->CharSets[FONTSUBST_FROM];
705 
706  if (CharSets[FONTSUBST_FROM] != DEFAULT_CHARSET &&
707  CharSets[FONTSUBST_FROM] != RequestedCharSet)
708  {
709  continue; /* not matched */
710  }
711 
712  /* does charset number exist? (to) */
713  if (pSubstEntry->CharSets[FONTSUBST_TO] != DEFAULT_CHARSET)
714  {
715  CharSets[FONTSUBST_TO] = pSubstEntry->CharSets[FONTSUBST_TO];
716  }
717  else
718  {
719  CharSets[FONTSUBST_TO] = RequestedCharSet;
720  }
721 
722  /* does font name match? */
723  if (!RtlEqualUnicodeString(&pSubstEntry->FontNames[FONTSUBST_FROM],
724  pInputName, TRUE))
725  {
726  continue; /* not matched */
727  }
728 
729  /* update *pOutputName */
730  *pOutputName = pSubstEntry->FontNames[FONTSUBST_TO];
731 
732  if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
733  {
734  /* update CharSetMap */
735  CharSetMap[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
736  CharSetMap[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
737  }
738  return TRUE; /* success */
739  }
740 
741  return FALSE;
742 }
743 
744 static VOID
745 IntUnicodeStringToBuffer(LPWSTR pszBuffer, USHORT cbBuffer, const UNICODE_STRING *pString)
746 {
747  USHORT cbLength = pString->Length;
748 
749  if (cbBuffer < sizeof(UNICODE_NULL))
750  return;
751 
752  if (cbLength > cbBuffer - sizeof(UNICODE_NULL))
753  cbLength = cbBuffer - sizeof(UNICODE_NULL);
754 
755  RtlCopyMemory(pszBuffer, pString->Buffer, cbLength);
756  pszBuffer[cbLength / sizeof(WCHAR)] = UNICODE_NULL;
757 }
758 
759 static BOOL
761 {
762  UINT RecurseCount = 5;
763  UNICODE_STRING OutputNameW = { 0 };
764  BYTE CharSetMap[FONTSUBST_FROM_AND_TO];
765  BOOL Found;
766  UNICODE_STRING InputNameW;
767 
768  if (pLogFont->lfFaceName[0] == UNICODE_NULL)
769  return FALSE;
770 
771  RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
772 
773  while (RecurseCount-- > 0)
774  {
775  Found = SubstituteFontByList(&g_FontSubstListHead,
776  &OutputNameW, &InputNameW,
777  pLogFont->lfCharSet, CharSetMap);
778  if (!Found)
779  break;
780 
781  IntUnicodeStringToBuffer(pLogFont->lfFaceName, sizeof(pLogFont->lfFaceName), &OutputNameW);
782 
783  if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
784  CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
785  {
786  pLogFont->lfCharSet = CharSetMap[FONTSUBST_TO];
787  }
788  }
789 
790  return TRUE; /* success */
791 }
792 
793 /*
794  * IntLoadSystemFonts
795  *
796  * Search the system font directory and adds each font found.
797  */
800 {
802  UNICODE_STRING Directory, FileName, TempString;
804  HANDLE hDirectory;
805  BYTE *DirInfoBuffer;
807  BOOLEAN bRestartScan = TRUE;
809  INT i;
810  static UNICODE_STRING SearchPatterns[] =
811  {
812  RTL_CONSTANT_STRING(L"*.ttf"),
813  RTL_CONSTANT_STRING(L"*.ttc"),
814  RTL_CONSTANT_STRING(L"*.otf"),
815  RTL_CONSTANT_STRING(L"*.otc"),
816  RTL_CONSTANT_STRING(L"*.fon"),
817  RTL_CONSTANT_STRING(L"*.fnt")
818  };
819 
820  RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
821 
823  &ObjectAttributes,
824  &Directory,
826  NULL,
827  NULL);
828 
829  Status = ZwOpenFile(
830  &hDirectory,
832  &ObjectAttributes,
833  &Iosb,
836 
837  if (NT_SUCCESS(Status))
838  {
839  for (i = 0; i < _countof(SearchPatterns); ++i)
840  {
841  DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
842  if (DirInfoBuffer == NULL)
843  {
844  ZwClose(hDirectory);
845  return;
846  }
847 
849  if (FileName.Buffer == NULL)
850  {
851  ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
852  ZwClose(hDirectory);
853  return;
854  }
855  FileName.Length = 0;
856  FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
857 
858  while (1)
859  {
860  Status = ZwQueryDirectoryFile(
861  hDirectory,
862  NULL,
863  NULL,
864  NULL,
865  &Iosb,
866  DirInfoBuffer,
867  0x4000,
869  FALSE,
870  &SearchPatterns[i],
871  bRestartScan);
872 
873  if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
874  {
875  break;
876  }
877 
878  DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
879  while (1)
880  {
881  TempString.Buffer = DirInfo->FileName;
882  TempString.Length =
883  TempString.MaximumLength = DirInfo->FileNameLength;
884  RtlCopyUnicodeString(&FileName, &Directory);
885  RtlAppendUnicodeStringToString(&FileName, &TempString);
886  IntGdiAddFontResource(&FileName, 0);
887  if (DirInfo->NextEntryOffset == 0)
888  break;
889  DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
890  }
891 
892  bRestartScan = FALSE;
893  }
894 
895  ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
896  ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
897  }
898  ZwClose(hDirectory);
899  }
900 }
901 
902 static BYTE
903 ItalicFromStyle(const char *style_name)
904 {
905  if (style_name == NULL || style_name[0] == 0)
906  return FALSE;
907  if (strstr(style_name, "Italic") != NULL)
908  return TRUE;
909  if (strstr(style_name, "Oblique") != NULL)
910  return TRUE;
911  return FALSE;
912 }
913 
914 static LONG
915 WeightFromStyle(const char *style_name)
916 {
917  if (style_name == NULL || style_name[0] == 0)
918  return FW_NORMAL;
919  if (strstr(style_name, "Regular") != NULL)
920  return FW_REGULAR;
921  if (strstr(style_name, "Normal") != NULL)
922  return FW_NORMAL;
923  if (strstr(style_name, "SemiBold") != NULL)
924  return FW_SEMIBOLD;
925  if (strstr(style_name, "UltraBold") != NULL)
926  return FW_ULTRABOLD;
927  if (strstr(style_name, "DemiBold") != NULL)
928  return FW_DEMIBOLD;
929  if (strstr(style_name, "ExtraBold") != NULL)
930  return FW_EXTRABOLD;
931  if (strstr(style_name, "Bold") != NULL)
932  return FW_BOLD;
933  if (strstr(style_name, "UltraLight") != NULL)
934  return FW_ULTRALIGHT;
935  if (strstr(style_name, "ExtraLight") != NULL)
936  return FW_EXTRALIGHT;
937  if (strstr(style_name, "Light") != NULL)
938  return FW_LIGHT;
939  if (strstr(style_name, "Hairline") != NULL)
940  return 50;
941  if (strstr(style_name, "Book") != NULL)
942  return 350;
943  if (strstr(style_name, "ExtraBlack") != NULL)
944  return 950;
945  if (strstr(style_name, "UltraBlack") != NULL)
946  return 1000;
947  if (strstr(style_name, "Black") != NULL)
948  return FW_BLACK;
949  if (strstr(style_name, "Medium") != NULL)
950  return FW_MEDIUM;
951  if (strstr(style_name, "Thin") != NULL)
952  return FW_THIN;
953  if (strstr(style_name, "Heavy") != NULL)
954  return FW_HEAVY;
955  return FW_NORMAL;
956 }
957 
958 static FT_Error
959 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight);
960 
961 static INT FASTCALL
963  PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
964 {
965  FT_Error Error;
967  FONT_ENTRY_MEM* PrivateEntry = NULL;
968  FONTGDI * FontGDI;
970  FT_Face Face;
972  FT_WinFNT_HeaderRec WinFNT;
973  INT FaceCount = 0, CharSetCount = 0;
974  PUNICODE_STRING pFileName = pLoadFont->pFileName;
975  DWORD Characteristics = pLoadFont->Characteristics;
976  PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
977  TT_OS2 * pOS2;
978  INT BitIndex;
979  FT_UShort os2_version;
980  FT_ULong os2_ulCodePageRange1;
981  FT_UShort os2_usWeightClass;
982 
983  if (SharedFace == NULL && CharSetIndex == -1)
984  {
985  /* load a face from memory */
986  IntLockFreeType();
987  Error = FT_New_Memory_Face(
988  g_FreeTypeLibrary,
989  pLoadFont->Memory->Buffer,
990  pLoadFont->Memory->BufferSize,
991  ((FontIndex != -1) ? FontIndex : 0),
992  &Face);
993 
994  if (!Error)
995  SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
996 
998 
999  if (!Error && FT_IS_SFNT(Face))
1000  pLoadFont->IsTrueType = TRUE;
1001 
1002  if (Error || SharedFace == NULL)
1003  {
1004  if (SharedFace)
1005  SharedFace_Release(SharedFace);
1006 
1007  if (Error == FT_Err_Unknown_File_Format)
1008  DPRINT1("Unknown font file format\n");
1009  else
1010  DPRINT1("Error reading font (error code: %d)\n", Error);
1011  return 0; /* failure */
1012  }
1013  }
1014  else
1015  {
1016  Face = SharedFace->Face;
1017  IntLockFreeType();
1018  SharedFace_AddRef(SharedFace);
1020  }
1021 
1022  /* allocate a FONT_ENTRY */
1024  if (!Entry)
1025  {
1026  SharedFace_Release(SharedFace);
1028  return 0; /* failure */
1029  }
1030 
1031  /* allocate a FONTGDI */
1032  FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
1033  if (!FontGDI)
1034  {
1035  SharedFace_Release(SharedFace);
1036  ExFreePoolWithTag(Entry, TAG_FONT);
1038  return 0; /* failure */
1039  }
1040 
1041  /* set file name */
1042  if (pFileName)
1043  {
1045  pFileName->Length + sizeof(UNICODE_NULL),
1046  GDITAG_PFF);
1047  if (FontGDI->Filename == NULL)
1048  {
1049  EngFreeMem(FontGDI);
1050  SharedFace_Release(SharedFace);
1051  ExFreePoolWithTag(Entry, TAG_FONT);
1053  return 0; /* failure */
1054  }
1055 
1056  RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
1057  FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1058  }
1059  else
1060  {
1061  FontGDI->Filename = NULL;
1062 
1063  PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT);
1064  if (!PrivateEntry)
1065  {
1066  if (FontGDI->Filename)
1068  EngFreeMem(FontGDI);
1069  SharedFace_Release(SharedFace);
1070  ExFreePoolWithTag(Entry, TAG_FONT);
1071  return 0;
1072  }
1073 
1074  PrivateEntry->Entry = Entry;
1075  if (pLoadFont->PrivateEntry)
1076  {
1077  InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry);
1078  }
1079  else
1080  {
1081  InitializeListHead(&PrivateEntry->ListEntry);
1082  pLoadFont->PrivateEntry = PrivateEntry;
1083  }
1084  }
1085 
1086  /* set face */
1087  FontGDI->SharedFace = SharedFace;
1088  FontGDI->CharSet = ANSI_CHARSET;
1089  FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name);
1090  FontGDI->RequestItalic = FALSE;
1091  FontGDI->OriginalWeight = WeightFromStyle(Face->style_name);
1092  FontGDI->RequestWeight = FW_NORMAL;
1093 
1094  RtlInitAnsiString(&AnsiString, Face->family_name);
1095  Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiString, TRUE);
1096  if (NT_SUCCESS(Status))
1097  {
1098  if (Face->style_name && Face->style_name[0] &&
1099  strcmp(Face->style_name, "Regular") != 0)
1100  {
1101  RtlInitAnsiString(&AnsiString, Face->style_name);
1102  Status = RtlAnsiStringToUnicodeString(&Entry->StyleName, &AnsiString, TRUE);
1103  if (!NT_SUCCESS(Status))
1104  {
1105  RtlFreeUnicodeString(&Entry->FaceName);
1106  }
1107  }
1108  else
1109  {
1111  }
1112  }
1113  if (!NT_SUCCESS(Status))
1114  {
1115  if (PrivateEntry)
1116  {
1117  if (pLoadFont->PrivateEntry == PrivateEntry)
1118  {
1119  pLoadFont->PrivateEntry = NULL;
1120  }
1121  else
1122  {
1123  RemoveEntryList(&PrivateEntry->ListEntry);
1124  }
1125  ExFreePoolWithTag(PrivateEntry, TAG_FONT);
1126  }
1127  if (FontGDI->Filename)
1129  EngFreeMem(FontGDI);
1130  SharedFace_Release(SharedFace);
1131  ExFreePoolWithTag(Entry, TAG_FONT);
1132  return 0;
1133  }
1134 
1135  os2_version = 0;
1136  IntLockFreeType();
1137  pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
1138  if (pOS2)
1139  {
1140  os2_version = pOS2->version;
1141  os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
1142  os2_usWeightClass = pOS2->usWeightClass;
1143  }
1145 
1146  if (pOS2 && os2_version >= 1)
1147  {
1148  /* get charset and weight from OS/2 header */
1149 
1150  /* Make sure we do not use this pointer anymore */
1151  pOS2 = NULL;
1152 
1153  for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
1154  {
1155  if (os2_ulCodePageRange1 & (1 << BitIndex))
1156  {
1157  if (g_FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
1158  continue;
1159 
1160  if ((CharSetIndex == -1 && CharSetCount == 0) ||
1161  CharSetIndex == CharSetCount)
1162  {
1163  FontGDI->CharSet = g_FontTci[BitIndex].ciCharset;
1164  }
1165 
1166  ++CharSetCount;
1167  }
1168  }
1169 
1170  /* set actual weight */
1171  FontGDI->OriginalWeight = os2_usWeightClass;
1172  }
1173  else
1174  {
1175  /* get charset from WinFNT header */
1176  IntLockFreeType();
1177  Error = FT_Get_WinFNT_Header(Face, &WinFNT);
1178  if (!Error)
1179  {
1180  FontGDI->CharSet = WinFNT.charset;
1181  }
1183  }
1184 
1185  /* FIXME: CharSet is invalid on Marlett */
1186  if (RtlEqualUnicodeString(&Entry->FaceName, &g_MarlettW, TRUE))
1187  {
1188  FontGDI->CharSet = SYMBOL_CHARSET;
1189  }
1190 
1191  ++FaceCount;
1192  DPRINT("Font loaded: %s (%s)\n",
1193  Face->family_name ? Face->family_name : "<NULL>",
1194  Face->style_name ? Face->style_name : "<NULL>");
1195  DPRINT("Num glyphs: %d\n", Face->num_glyphs);
1196  DPRINT("CharSet: %d\n", FontGDI->CharSet);
1197 
1198  IntLockFreeType();
1199  IntRequestFontSize(NULL, FontGDI, 0, 0);
1201 
1202  /* Add this font resource to the font table */
1203  Entry->Font = FontGDI;
1204  Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
1205 
1206  if (Characteristics & FR_PRIVATE)
1207  {
1208  /* private font */
1210  IntLockProcessPrivateFonts(Win32Process);
1211  InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
1212  IntUnLockProcessPrivateFonts(Win32Process);
1213  }
1214  else
1215  {
1216  /* global font */
1218  InsertTailList(&g_FontListHead, &Entry->ListEntry);
1220  }
1221 
1222  if (FontIndex == -1)
1223  {
1224  if (FT_IS_SFNT(Face))
1225  {
1226  TT_Face TrueType = (TT_Face)Face;
1227  if (TrueType->ttc_header.count > 1)
1228  {
1229  FT_Long i;
1230  for (i = 1; i < TrueType->ttc_header.count; ++i)
1231  {
1232  FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
1233  }
1234  }
1235  }
1236  FontIndex = 0;
1237  }
1238 
1239  if (CharSetIndex == -1)
1240  {
1241  INT i;
1242  USHORT NameLength = Entry->FaceName.Length;
1243 
1244  if (Entry->StyleName.Length)
1245  NameLength += Entry->StyleName.Length + sizeof(WCHAR);
1246 
1247  if (pLoadFont->RegValueName.Length == 0)
1248  {
1249  pValueName->Length = 0;
1250  pValueName->MaximumLength = NameLength + sizeof(WCHAR);
1251  pValueName->Buffer = ExAllocatePoolWithTag(PagedPool,
1252  pValueName->MaximumLength,
1253  TAG_USTR);
1254  pValueName->Buffer[0] = UNICODE_NULL;
1255  RtlAppendUnicodeStringToString(pValueName, &Entry->FaceName);
1256  }
1257  else
1258  {
1259  UNICODE_STRING NewString;
1260  USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + NameLength;
1261  NewString.Length = 0;
1262  NewString.MaximumLength = Length + sizeof(WCHAR);
1264  NewString.MaximumLength,
1265  TAG_USTR);
1266  NewString.Buffer[0] = UNICODE_NULL;
1267 
1268  RtlAppendUnicodeStringToString(&NewString, pValueName);
1269  RtlAppendUnicodeToString(&NewString, L" & ");
1270  RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
1271 
1272  RtlFreeUnicodeString(pValueName);
1273  *pValueName = NewString;
1274  }
1275  if (Entry->StyleName.Length)
1276  {
1277  RtlAppendUnicodeToString(pValueName, L" ");
1278  RtlAppendUnicodeStringToString(pValueName, &Entry->StyleName);
1279  }
1280 
1281  for (i = 1; i < CharSetCount; ++i)
1282  {
1283  /* Do not count charsets towards 'faces' loaded */
1284  IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
1285  }
1286  }
1287 
1288  return FaceCount; /* number of loaded faces */
1289 }
1290 
1291 /*
1292  * IntGdiAddFontResource
1293  *
1294  * Adds the font resource from the specified file to the system.
1295  */
1296 
1297 INT FASTCALL
1299 {
1300  NTSTATUS Status;
1302  PVOID Buffer = NULL;
1305  SIZE_T ViewSize = 0;
1306  LARGE_INTEGER SectionSize;
1309  INT FontCount;
1310  HANDLE KeyHandle;
1311  static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
1312 
1313  /* Open the font file */
1314  InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
1315  Status = ZwOpenFile(
1316  &FileHandle,
1318  &ObjectAttributes,
1319  &Iosb,
1322  if (!NT_SUCCESS(Status))
1323  {
1324  DPRINT("Could not load font file: %wZ\n", FileName);
1325  return 0;
1326  }
1327 
1328  SectionSize.QuadPart = 0LL;
1329  Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
1330  NULL, &SectionSize, PAGE_READONLY,
1331  SEC_COMMIT, FileHandle, NULL);
1332  if (!NT_SUCCESS(Status))
1333  {
1334  DPRINT("Could not map file: %wZ\n", FileName);
1335  ZwClose(FileHandle);
1336  return 0;
1337  }
1338  ZwClose(FileHandle);
1339 
1340  Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
1341  if (!NT_SUCCESS(Status))
1342  {
1343  DPRINT("Could not map file: %wZ\n", FileName);
1344  ObDereferenceObject(SectionObject);
1345  return 0;
1346  }
1347 
1348  LoadFont.pFileName = FileName;
1349  LoadFont.Memory = SharedMem_Create(Buffer, ViewSize, TRUE);
1350  LoadFont.Characteristics = Characteristics;
1352  LoadFont.IsTrueType = FALSE;
1353  LoadFont.PrivateEntry = NULL;
1354  FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1355 
1356  ObDereferenceObject(SectionObject);
1357 
1358  /* Release our copy */
1359  IntLockFreeType();
1360  SharedMem_Release(LoadFont.Memory);
1362 
1363  if (FontCount > 0)
1364  {
1365  if (LoadFont.IsTrueType)
1366  {
1367  /* append " (TrueType)" */
1368  UNICODE_STRING NewString;
1369  USHORT Length;
1370 
1371  Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length;
1372  NewString.Length = 0;
1373  NewString.MaximumLength = Length + sizeof(WCHAR);
1375  NewString.MaximumLength,
1376  TAG_USTR);
1377  NewString.Buffer[0] = UNICODE_NULL;
1378 
1379  RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
1380  RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
1382  LoadFont.RegValueName = NewString;
1383  }
1384 
1385  /* registry */
1386  InitializeObjectAttributes(&ObjectAttributes, &g_FontRegPath,
1388  NULL, NULL);
1389  Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
1390  if (NT_SUCCESS(Status))
1391  {
1392  SIZE_T DataSize;
1393  LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
1394  if (pFileName)
1395  {
1396  pFileName++;
1397  DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
1398  ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
1399  pFileName, DataSize);
1400  }
1401  ZwClose(KeyHandle);
1402  }
1403  }
1405 
1406  return FontCount;
1407 }
1408 
1411 {
1413  FONT_ENTRY_COLL_MEM* EntryCollection;
1414  INT FaceCount;
1415  HANDLE Ret = 0;
1416 
1417  PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
1418 
1419  if (!BufferCopy)
1420  {
1421  *pNumAdded = 0;
1422  return NULL;
1423  }
1424  memcpy(BufferCopy, Buffer, dwSize);
1425 
1426  LoadFont.pFileName = NULL;
1427  LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
1428  LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
1430  LoadFont.IsTrueType = FALSE;
1431  LoadFont.PrivateEntry = NULL;
1432  FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1433 
1435 
1436  /* Release our copy */
1437  IntLockFreeType();
1438  SharedMem_Release(LoadFont.Memory);
1440 
1441  if (FaceCount > 0)
1442  {
1443  EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
1444  if (EntryCollection)
1445  {
1447  EntryCollection->Entry = LoadFont.PrivateEntry;
1448  IntLockProcessPrivateFonts(Win32Process);
1449  EntryCollection->Handle = ULongToHandle(++Win32Process->PrivateMemFontHandleCount);
1450  InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
1451  IntUnLockProcessPrivateFonts(Win32Process);
1452  Ret = EntryCollection->Handle;
1453  }
1454  }
1455  *pNumAdded = FaceCount;
1456 
1457  return Ret;
1458 }
1459 
1460 // FIXME: Add RemoveFontResource
1461 
1462 static VOID FASTCALL
1464 {
1465  PFONTGDI FontGDI = FontEntry->Font;
1466  PSHARED_FACE SharedFace = FontGDI->SharedFace;
1467 
1468  if (FontGDI->Filename)
1470 
1471  EngFreeMem(FontGDI);
1472  SharedFace_Release(SharedFace);
1473  ExFreePoolWithTag(FontEntry, TAG_FONT);
1474 }
1475 
1476 VOID FASTCALL
1478 {
1480  PFONT_ENTRY_MEM FontEntry;
1481 
1482  while (!IsListEmpty(&Head->ListEntry))
1483  {
1484  Entry = RemoveHeadList(&Head->ListEntry);
1485  FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
1486 
1487  CleanupFontEntry(FontEntry->Entry);
1488  ExFreePoolWithTag(FontEntry, TAG_FONT);
1489  }
1490 
1491  CleanupFontEntry(Head->Entry);
1492  ExFreePoolWithTag(Head, TAG_FONT);
1493 }
1494 
1495 static VOID FASTCALL
1497 {
1498  PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
1499  PLIST_ENTRY ListEntry;
1500  RemoveEntryList(&Collection->ListEntry);
1501 
1502  do {
1503  /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
1504  RemoveEntryList(&FontMemEntry->Entry->ListEntry);
1505 
1506  ListEntry = FontMemEntry->ListEntry.Flink;
1507  FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
1508 
1509  } while (FontMemEntry != Collection->Entry);
1510 }
1511 
1512 BOOL FASTCALL
1514 {
1516  PFONT_ENTRY_COLL_MEM CurrentEntry;
1517  PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
1519 
1520  IntLockProcessPrivateFonts(Win32Process);
1521  for (Entry = Win32Process->PrivateMemFontListHead.Flink;
1522  Entry != &Win32Process->PrivateMemFontListHead;
1523  Entry = Entry->Flink)
1524  {
1525  CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1526 
1527  if (CurrentEntry->Handle == hMMFont)
1528  {
1529  EntryCollection = CurrentEntry;
1530  UnlinkFontMemCollection(CurrentEntry);
1531  break;
1532  }
1533  }
1534  IntUnLockProcessPrivateFonts(Win32Process);
1535 
1536  if (EntryCollection)
1537  {
1538  IntGdiCleanupMemEntry(EntryCollection->Entry);
1539  ExFreePoolWithTag(EntryCollection, TAG_FONT);
1540  return TRUE;
1541  }
1542  return FALSE;
1543 }
1544 
1545 
1546 VOID FASTCALL
1548 {
1551  PFONT_ENTRY_COLL_MEM EntryCollection;
1552 
1553  DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
1554  do {
1555  Entry = NULL;
1556  EntryCollection = NULL;
1557 
1558  IntLockProcessPrivateFonts(Win32Process);
1559  if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
1560  {
1561  Entry = Win32Process->PrivateMemFontListHead.Flink;
1562  EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1563  UnlinkFontMemCollection(EntryCollection);
1564  }
1565  IntUnLockProcessPrivateFonts(Win32Process);
1566 
1567  if (EntryCollection)
1568  {
1569  IntGdiCleanupMemEntry(EntryCollection->Entry);
1570  ExFreePoolWithTag(EntryCollection, TAG_FONT);
1571  }
1572  else
1573  {
1574  /* No Mem fonts anymore, see if we have any other private fonts left */
1575  Entry = NULL;
1576  IntLockProcessPrivateFonts(Win32Process);
1577  if (!IsListEmpty(&Win32Process->PrivateFontListHead))
1578  {
1579  Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
1580  }
1581  IntUnLockProcessPrivateFonts(Win32Process);
1582 
1583  if (Entry)
1584  {
1585  CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
1586  }
1587  }
1588 
1589  } while (Entry);
1590 }
1591 
1592 BOOL FASTCALL
1594 {
1595  BOOL Ret = g_RenderingEnabled;
1596  HDC hDC;
1597 
1598  hDC = IntGetScreenDC();
1599  if (hDC)
1600  Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && g_RenderingEnabled;
1601 
1602  return Ret;
1603 }
1604 
1605 VOID FASTCALL
1607 {
1609 }
1610 
1613 {
1614  switch (logfont->lfQuality)
1615  {
1616  case ANTIALIASED_QUALITY:
1617  break;
1619  return FT_RENDER_MODE_MONO;
1620  case DRAFT_QUALITY:
1621  return FT_RENDER_MODE_LIGHT;
1622  /* case CLEARTYPE_QUALITY:
1623  return FT_RENDER_MODE_LCD; */
1624  }
1625  return FT_RENDER_MODE_NORMAL;
1626 }
1627 
1628 
1631 {
1632  PLFONT plfont;
1633  LOGFONTW *plf;
1634 
1635  ASSERT(lf);
1636  plfont = LFONT_AllocFontWithHandle();
1637  if (!plfont)
1638  {
1639  return STATUS_NO_MEMORY;
1640  }
1641 
1642  ExInitializePushLock(&plfont->lock);
1643  *NewFont = plfont->BaseObject.hHmgr;
1644  plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
1645  RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
1646  if (lf->lfEscapement != lf->lfOrientation)
1647  {
1648  /* This should really depend on whether GM_ADVANCED is set */
1649  plf->lfOrientation = plf->lfEscapement;
1650  }
1651  LFONT_UnlockFont(plfont);
1652 
1653  return STATUS_SUCCESS;
1654 }
1655 
1656 /*************************************************************************
1657  * TranslateCharsetInfo
1658  *
1659  * Fills a CHARSETINFO structure for a character set, code page, or
1660  * font. This allows making the correspondance between different labelings
1661  * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
1662  * of the same encoding.
1663  *
1664  * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
1665  * only one codepage should be set in *Src.
1666  *
1667  * RETURNS
1668  * TRUE on success, FALSE on failure.
1669  *
1670  */
1671 static BOOLEAN APIENTRY
1673  if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
1674  if flags == TCI_SRCCHARSET: a character set value
1675  if flags == TCI_SRCCODEPAGE: a code page value */
1676  LPCHARSETINFO Cs, /* [out] structure to receive charset information */
1677  DWORD Flags /* [in] determines interpretation of lpSrc */)
1678 {
1679  int Index = 0;
1680 
1681  switch (Flags)
1682  {
1683  case TCI_SRCFONTSIG:
1684  while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
1685  {
1686  Index++;
1687  }
1688  break;
1689  case TCI_SRCCODEPAGE:
1690  while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciACP)
1691  {
1692  Index++;
1693  }
1694  break;
1695  case TCI_SRCCHARSET:
1696  while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciCharset)
1697  {
1698  Index++;
1699  }
1700  break;
1701  case TCI_SRCLOCALE:
1702  UNIMPLEMENTED;
1703  return FALSE;
1704  default:
1705  return FALSE;
1706  }
1707 
1708  if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == g_FontTci[Index].ciCharset)
1709  {
1710  return FALSE;
1711  }
1712 
1713  RtlCopyMemory(Cs, &g_FontTci[Index], sizeof(CHARSETINFO));
1714 
1715  return TRUE;
1716 }
1717 
1718 
1720 {
1721  int i;
1722 
1723  for(i = 0; i < ft_face->num_charmaps; i++)
1724  {
1725  if (ft_face->charmaps[i]->platform_id == TT_PLATFORM_MICROSOFT &&
1726  ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
1727  {
1728  return TRUE;
1729  }
1730  }
1731  return FALSE;
1732 }
1733 
1734 static void FASTCALL
1736  TT_OS2 *pOS2, TT_HoriHeader *pHori,
1737  FT_WinFNT_HeaderRec *pFNT, BOOL RealFont)
1738 {
1739  FT_Fixed XScale, YScale;
1740  int Ascent, Descent;
1741  FT_Face Face = FontGDI->SharedFace->Face;
1742 
1744 
1745  XScale = Face->size->metrics.x_scale;
1746  YScale = Face->size->metrics.y_scale;
1747 
1748  if (pFNT)
1749  {
1750  TM->tmHeight = pFNT->pixel_height;
1751  TM->tmAscent = pFNT->ascent;
1752  TM->tmDescent = TM->tmHeight - TM->tmAscent;
1753  TM->tmInternalLeading = pFNT->internal_leading;
1754  TM->tmExternalLeading = pFNT->external_leading;
1755  TM->tmAveCharWidth = pFNT->avg_width;
1756  TM->tmMaxCharWidth = pFNT->max_width;
1757  TM->tmOverhang = 0;
1760  TM->tmFirstChar = pFNT->first_char;
1761  TM->tmLastChar = pFNT->last_char;
1762  TM->tmDefaultChar = pFNT->default_char + pFNT->first_char;
1763  TM->tmBreakChar = pFNT->break_char + pFNT->first_char;
1764  TM->tmPitchAndFamily = pFNT->pitch_and_family;
1765  if (RealFont)
1766  {
1767  TM->tmWeight = FontGDI->OriginalWeight;
1768  TM->tmItalic = FontGDI->OriginalItalic;
1769  TM->tmUnderlined = pFNT->underline;
1770  TM->tmStruckOut = pFNT->strike_out;
1771  TM->tmCharSet = pFNT->charset;
1772  }
1773  else
1774  {
1775  TM->tmWeight = FontGDI->RequestWeight;
1776  TM->tmItalic = FontGDI->RequestItalic;
1777  TM->tmUnderlined = FontGDI->RequestUnderline;
1778  TM->tmStruckOut = FontGDI->RequestStrikeOut;
1779  TM->tmCharSet = FontGDI->CharSet;
1780  }
1781  return;
1782  }
1783 
1784  if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
1785  {
1786  Ascent = pHori->Ascender;
1787  Descent = -pHori->Descender;
1788  }
1789  else
1790  {
1791  Ascent = pOS2->usWinAscent;
1792  Descent = pOS2->usWinDescent;
1793  }
1794 
1795  if (FontGDI->Magic != FONTGDI_MAGIC)
1796  {
1797  IntRequestFontSize(NULL, FontGDI, 0, 0);
1798  }
1799  TM->tmAscent = FontGDI->tmAscent;
1800  TM->tmDescent = FontGDI->tmDescent;
1801  TM->tmHeight = TM->tmAscent + TM->tmDescent;
1802  TM->tmInternalLeading = FontGDI->tmInternalLeading;
1803 
1804  /* MSDN says:
1805  * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1806  */
1807  TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
1808  - ((Ascent + Descent)
1809  - (pHori->Ascender - pHori->Descender)),
1810  YScale) + 32) >> 6);
1811 
1812  TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
1813  if (TM->tmAveCharWidth == 0)
1814  {
1815  TM->tmAveCharWidth = 1;
1816  }
1817 
1818  /* Correct forumla to get the maxcharwidth from unicode and ansi font */
1819  TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
1820 
1821  if (RealFont)
1822  {
1823  TM->tmWeight = FontGDI->OriginalWeight;
1824  }
1825  else
1826  {
1827  if (FontGDI->OriginalWeight != FW_DONTCARE &&
1828  FontGDI->OriginalWeight != FW_NORMAL)
1829  {
1830  TM->tmWeight = FontGDI->OriginalWeight;
1831  }
1832  else
1833  {
1834  TM->tmWeight = FontGDI->RequestWeight;
1835  }
1836  }
1837 
1838  TM->tmOverhang = 0;
1839  TM->tmDigitizedAspectX = 96;
1840  TM->tmDigitizedAspectY = 96;
1841  if (face_has_symbol_charmap(Face) ||
1842  (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
1843  {
1844  USHORT cpOEM, cpAnsi;
1845 
1846  EngGetCurrentCodePage(&cpOEM, &cpAnsi);
1847  TM->tmFirstChar = 0;
1848  switch(cpAnsi)
1849  {
1850  case 1257: /* Baltic */
1851  TM->tmLastChar = 0xf8fd;
1852  break;
1853  default:
1854  TM->tmLastChar = 0xf0ff;
1855  }
1856  TM->tmBreakChar = 0x20;
1857  TM->tmDefaultChar = 0x1f;
1858  }
1859  else
1860  {
1861  TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
1862  TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
1863 
1864  if(pOS2->usFirstCharIndex <= 1)
1865  TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
1866  else if (pOS2->usFirstCharIndex > 0xff)
1867  TM->tmBreakChar = 0x20;
1868  else
1869  TM->tmBreakChar = pOS2->usFirstCharIndex;
1870  TM->tmDefaultChar = TM->tmBreakChar - 1;
1871  }
1872 
1873  if (RealFont)
1874  {
1875  TM->tmItalic = FontGDI->OriginalItalic;
1876  TM->tmUnderlined = FALSE;
1877  TM->tmStruckOut = FALSE;
1878  }
1879  else
1880  {
1881  if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
1882  {
1883  TM->tmItalic = 0xFF;
1884  }
1885  else
1886  {
1887  TM->tmItalic = 0;
1888  }
1889  TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
1890  TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
1891  }
1892 
1893  if (!FT_IS_FIXED_WIDTH(Face))
1894  {
1895  switch (pOS2->panose[PAN_PROPORTION_INDEX])
1896  {
1897  case PAN_PROP_MONOSPACED:
1898  TM->tmPitchAndFamily = 0;
1899  break;
1900  default:
1902  break;
1903  }
1904  }
1905  else
1906  {
1907  TM->tmPitchAndFamily = 0;
1908  }
1909 
1910  switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
1911  {
1912  case PAN_FAMILY_SCRIPT:
1913  TM->tmPitchAndFamily |= FF_SCRIPT;
1914  break;
1915  case PAN_FAMILY_DECORATIVE:
1917  break;
1918 
1919  case PAN_ANY:
1920  case PAN_NO_FIT:
1922  case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
1923  /* Which is clearly not what the panose spec says. */
1924  if (TM->tmPitchAndFamily == 0) /* Fixed */
1925  {
1927  }
1928  else
1929  {
1930  switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
1931  {
1932  case PAN_ANY:
1933  case PAN_NO_FIT:
1934  default:
1936  break;
1937 
1938  case PAN_SERIF_COVE:
1939  case PAN_SERIF_OBTUSE_COVE:
1940  case PAN_SERIF_SQUARE_COVE:
1942  case PAN_SERIF_SQUARE:
1943  case PAN_SERIF_THIN:
1944  case PAN_SERIF_BONE:
1945  case PAN_SERIF_EXAGGERATED:
1946  case PAN_SERIF_TRIANGLE:
1947  TM->tmPitchAndFamily |= FF_ROMAN;
1948  break;
1949 
1950  case PAN_SERIF_NORMAL_SANS:
1951  case PAN_SERIF_OBTUSE_SANS:
1952  case PAN_SERIF_PERP_SANS:
1953  case PAN_SERIF_FLARED:
1954  case PAN_SERIF_ROUNDED:
1955  TM->tmPitchAndFamily |= FF_SWISS;
1956  break;
1957  }
1958  }
1959  break;
1960  default:
1962  }
1963 
1964  if (FT_IS_SCALABLE(Face))
1965  {
1967  }
1968  if (FT_IS_SFNT(Face))
1969  {
1971  }
1972 
1973  TM->tmCharSet = FontGDI->CharSet;
1974 }
1975 
1976 static void FASTCALL
1978  TT_OS2 *pOS2, TT_HoriHeader *pHori,
1979  FT_WinFNT_HeaderRec *pFNT)
1980 {
1981  FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
1982 }
1983 
1984 static NTSTATUS
1986  FT_UShort NameID, FT_UShort LangID);
1987 
1988 typedef struct FONT_NAMES
1989 {
1990  UNICODE_STRING FamilyNameW; /* family name (TT_NAME_ID_FONT_FAMILY) */
1991  UNICODE_STRING FaceNameW; /* face name (TT_NAME_ID_FULL_NAME) */
1992  UNICODE_STRING StyleNameW; /* style name (TT_NAME_ID_FONT_SUBFAMILY) */
1993  UNICODE_STRING FullNameW; /* unique name (TT_NAME_ID_UNIQUE_ID) */
1994  ULONG OtmSize; /* size of OUTLINETEXTMETRICW with extra data */
1996 
1997 static __inline void FASTCALL
1999 {
2000  ULONG OtmSize;
2001 
2006 
2007  /* family name */
2009  /* face name */
2011  /* style name */
2013  /* unique name (full name) */
2015 
2016  /* Calculate the size of OUTLINETEXTMETRICW with extra data */
2017  OtmSize = sizeof(OUTLINETEXTMETRICW) +
2018  Names->FamilyNameW.Length + sizeof(UNICODE_NULL) +
2019  Names->FaceNameW.Length + sizeof(UNICODE_NULL) +
2020  Names->StyleNameW.Length + sizeof(UNICODE_NULL) +
2021  Names->FullNameW.Length + sizeof(UNICODE_NULL);
2022  Names->OtmSize = OtmSize;
2023 }
2024 
2025 static __inline SIZE_T FASTCALL
2027 {
2028  RtlCopyMemory(pb, pName->Buffer, pName->Length);
2029  *(WCHAR *)&pb[pName->Length] = UNICODE_NULL;
2030  return pName->Length + sizeof(UNICODE_NULL);
2031 }
2032 
2033 static __inline BYTE *FASTCALL
2035 {
2036  BYTE *pb = (BYTE *)Otm + sizeof(OUTLINETEXTMETRICW);
2037 
2038  /* family name */
2039  Otm->otmpFamilyName = (LPSTR)(pb - (BYTE*) Otm);
2040  pb += IntStoreName(&Names->FamilyNameW, pb);
2041 
2042  /* face name */
2043  Otm->otmpFaceName = (LPSTR)(pb - (BYTE*) Otm);
2044  pb += IntStoreName(&Names->FaceNameW, pb);
2045 
2046  /* style name */
2047  Otm->otmpStyleName = (LPSTR)(pb - (BYTE*) Otm);
2048  pb += IntStoreName(&Names->StyleNameW, pb);
2049 
2050  /* unique name (full name) */
2051  Otm->otmpFullName = (LPSTR)(pb - (BYTE*) Otm);
2052  pb += IntStoreName(&Names->FullNameW, pb);
2053 
2054  return pb;
2055 }
2056 
2057 static __inline void FASTCALL
2059 {
2064 }
2065 
2066 /*************************************************************
2067  * IntGetOutlineTextMetrics
2068  *
2069  */
2070 INT FASTCALL
2072  UINT Size,
2073  OUTLINETEXTMETRICW *Otm)
2074 {
2075  TT_OS2 *pOS2;
2076  TT_HoriHeader *pHori;
2077  TT_Postscript *pPost;
2078  FT_Fixed XScale, YScale;
2079  FT_WinFNT_HeaderRec WinFNT;
2080  FT_Error Error;
2081  BYTE *pb;
2082  FONT_NAMES FontNames;
2083  PSHARED_FACE SharedFace = FontGDI->SharedFace;
2085  FT_Face Face = SharedFace->Face;
2086 
2088  {
2089  Cache = &SharedFace->EnglishUS;
2090  }
2091  else
2092  {
2093  Cache = &SharedFace->UserLanguage;
2094  }
2095 
2096  if (Cache->OutlineRequiredSize && Size < Cache->OutlineRequiredSize)
2097  {
2098  return Cache->OutlineRequiredSize;
2099  }
2100 
2101  IntInitFontNames(&FontNames, SharedFace);
2102 
2103  if (!Cache->OutlineRequiredSize)
2104  {
2105  Cache->OutlineRequiredSize = FontNames.OtmSize;
2106  }
2107 
2108  if (Size < Cache->OutlineRequiredSize)
2109  {
2110  IntFreeFontNames(&FontNames);
2111  return Cache->OutlineRequiredSize;
2112  }
2113 
2114  XScale = Face->size->metrics.x_scale;
2115  YScale = Face->size->metrics.y_scale;
2116 
2117  IntLockFreeType();
2118 
2119  pOS2 = FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
2120  if (NULL == pOS2)
2121  {
2123  DPRINT1("Can't find OS/2 table - not TT font?\n");
2124  IntFreeFontNames(&FontNames);
2125  return 0;
2126  }
2127 
2128  pHori = FT_Get_Sfnt_Table(Face, FT_SFNT_HHEA);
2129  if (NULL == pHori)
2130  {
2132  DPRINT1("Can't find HHEA table - not TT font?\n");
2133  IntFreeFontNames(&FontNames);
2134  return 0;
2135  }
2136 
2137  pPost = FT_Get_Sfnt_Table(Face, FT_SFNT_POST); /* We can live with this failing */
2138 
2139  Error = FT_Get_WinFNT_Header(Face, &WinFNT);
2140 
2141  Otm->otmSize = Cache->OutlineRequiredSize;
2142 
2143  FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &WinFNT : 0);
2144 
2145  Otm->otmFiller = 0;
2147  Otm->otmfsSelection = pOS2->fsSelection;
2148  Otm->otmfsType = pOS2->fsType;
2149  Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2150  Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2151  Otm->otmItalicAngle = 0; /* POST table */
2152  Otm->otmEMSquare = Face->units_per_EM;
2153 
2154 #define SCALE_X(value) ((FT_MulFix((value), XScale) + 32) >> 6)
2155 #define SCALE_Y(value) ((FT_MulFix((value), YScale) + 32) >> 6)
2156 
2157  Otm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
2158  Otm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
2159  Otm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
2160  Otm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
2161  Otm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
2162  Otm->otmrcFontBox.left = SCALE_X(Face->bbox.xMin);
2163  Otm->otmrcFontBox.right = SCALE_X(Face->bbox.xMax);
2164  Otm->otmrcFontBox.top = SCALE_Y(Face->bbox.yMax);
2165  Otm->otmrcFontBox.bottom = SCALE_Y(Face->bbox.yMin);
2166  Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
2167  Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
2168  Otm->otmMacLineGap = Otm->otmLineGap;
2169  Otm->otmusMinimumPPEM = 0; /* TT Header */
2180 
2181  if (!pPost)
2182  {
2183  Otm->otmsUnderscoreSize = 0;
2184  Otm->otmsUnderscorePosition = 0;
2185  }
2186  else
2187  {
2190  }
2191 
2192 #undef SCALE_X
2193 #undef SCALE_Y
2194 
2196 
2197  pb = IntStoreFontNames(&FontNames, Otm);
2198  ASSERT(pb - (BYTE*)Otm == Cache->OutlineRequiredSize);
2199 
2200  IntFreeFontNames(&FontNames);
2201 
2202  return Cache->OutlineRequiredSize;
2203 }
2204 
2205 static PFONTGDI FASTCALL
2207 {
2209  PFONT_ENTRY CurrentEntry;
2210  ANSI_STRING EntryFaceNameA;
2211  UNICODE_STRING EntryFaceNameW;
2212  FONTGDI *FontGDI;
2213  NTSTATUS status;
2214 
2215  for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
2216  {
2217  CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2218 
2219  FontGDI = CurrentEntry->Font;
2220  ASSERT(FontGDI);
2221 
2222  RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
2223  status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2224  if (!NT_SUCCESS(status))
2225  {
2226  break;
2227  }
2228 
2229  if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2230  {
2231  EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2232  EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2233  }
2234 
2235  if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE))
2236  {
2237  RtlFreeUnicodeString(&EntryFaceNameW);
2238  return FontGDI;
2239  }
2240 
2241  RtlFreeUnicodeString(&EntryFaceNameW);
2242  }
2243 
2244  return NULL;
2245 }
2246 
2247 static PFONTGDI FASTCALL
2249 {
2250  PPROCESSINFO Win32Process;
2251  PFONTGDI Font;
2252 
2253  /* Search the process local list.
2254  We do not have to search the 'Mem' list, since those fonts are linked in the PrivateFontListHead */
2255  Win32Process = PsGetCurrentProcessWin32Process();
2256  IntLockProcessPrivateFonts(Win32Process);
2257  Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
2258  IntUnLockProcessPrivateFonts(Win32Process);
2259  if (NULL != Font)
2260  {
2261  return Font;
2262  }
2263 
2264  /* Search the global list */
2266  Font = FindFaceNameInList(FaceName, &g_FontListHead);
2268 
2269  return Font;
2270 }
2271 
2272 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
2273 static BYTE
2275 {
2276  /* FIXME: Add more and fix if wrong */
2277  switch (PRIMARYLANGID(LangID))
2278  {
2279  case LANG_CHINESE:
2280  switch (SUBLANGID(LangID))
2281  {
2283  return CHINESEBIG5_CHARSET;
2285  default:
2286  break;
2287  }
2288  return GB2312_CHARSET;
2289 
2290  case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
2291  case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
2292  return EASTEUROPE_CHARSET;
2293 
2294  case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
2295  case LANG_SERBIAN: case LANG_UKRAINIAN:
2296  return RUSSIAN_CHARSET;
2297 
2298  case LANG_ARABIC: return ARABIC_CHARSET;
2299  case LANG_GREEK: return GREEK_CHARSET;
2300  case LANG_HEBREW: return HEBREW_CHARSET;
2301  case LANG_JAPANESE: return SHIFTJIS_CHARSET;
2302  case LANG_KOREAN: return JOHAB_CHARSET;
2303  case LANG_TURKISH: return TURKISH_CHARSET;
2304  case LANG_THAI: return THAI_CHARSET;
2305  case LANG_LATVIAN: return BALTIC_CHARSET;
2306  case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
2307 
2308  case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
2309  case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
2310  case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
2311  case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
2312  case LANG_SWEDISH: default:
2313  return ANSI_CHARSET;
2314  }
2315 }
2316 
2317 static void
2319 {
2320  BYTE b, *pb = pvData;
2321  Size /= 2;
2322  while (Size-- > 0)
2323  {
2324  b = pb[0];
2325  pb[0] = pb[1];
2326  pb[1] = b;
2327  ++pb; ++pb;
2328  }
2329 }
2330 
2331 static NTSTATUS
2333 {
2335  UNICODE_STRING Tmp;
2336 
2338  if (Tmp.Buffer)
2339  {
2340  Tmp.MaximumLength = Source->MaximumLength;
2341  Tmp.Length = 0;
2342  RtlCopyUnicodeString(&Tmp, Source);
2343 
2344  Destination->MaximumLength = Tmp.MaximumLength;
2345  Destination->Length = Tmp.Length;
2346  Destination->Buffer = Tmp.Buffer;
2347 
2348  Status = STATUS_SUCCESS;
2349  }
2350 
2351  return Status;
2352 }
2353 
2354 static NTSTATUS
2356  FT_UShort NameID, FT_UShort LangID)
2357 {
2358  FT_SfntName Name;
2359  INT i, Count, BestIndex, Score, BestScore;
2360  FT_Error Error;
2362  ANSI_STRING AnsiName;
2364  FT_Face Face = SharedFace->Face;
2365 
2366  RtlFreeUnicodeString(pNameW);
2367 
2368  /* select cache */
2369  if (PRIMARYLANGID(LangID) == LANG_ENGLISH)
2370  {
2371  Cache = &SharedFace->EnglishUS;
2372  }
2373  else
2374  {
2375  Cache = &SharedFace->UserLanguage;
2376  }
2377 
2378  /* use cache if available */
2379  if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer)
2380  {
2381  return DuplicateUnicodeString(&Cache->FontFamily, pNameW);
2382  }
2383  if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer)
2384  {
2385  return DuplicateUnicodeString(&Cache->FullName, pNameW);
2386  }
2387 
2388  BestIndex = -1;
2389  BestScore = 0;
2390 
2391  Count = FT_Get_Sfnt_Name_Count(Face);
2392  for (i = 0; i < Count; ++i)
2393  {
2394  Error = FT_Get_Sfnt_Name(Face, i, &Name);
2395  if (Error)
2396  {
2397  continue; /* failure */
2398  }
2399 
2400  if (Name.name_id != NameID)
2401  {
2402  continue; /* mismatched */
2403  }
2404 
2405  if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
2406  (Name.encoding_id != TT_MS_ID_UNICODE_CS &&
2407  Name.encoding_id != TT_MS_ID_SYMBOL_CS))
2408  {
2409  continue; /* not Microsoft Unicode name */
2410  }
2411 
2412  if (Name.string == NULL || Name.string_len == 0 ||
2413  (Name.string[0] == 0 && Name.string[1] == 0))
2414  {
2415  continue; /* invalid string */
2416  }
2417 
2418  if (Name.language_id == LangID)
2419  {
2420  Score = 30;
2421  BestIndex = i;
2422  break; /* best match */
2423  }
2424  else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID))
2425  {
2426  Score = 20;
2427  }
2428  else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH)
2429  {
2430  Score = 10;
2431  }
2432  else
2433  {
2434  Score = 0;
2435  }
2436 
2437  if (Score > BestScore)
2438  {
2439  BestScore = Score;
2440  BestIndex = i;
2441  }
2442  }
2443 
2444  if (BestIndex >= 0)
2445  {
2446  /* store the best name */
2447  Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
2448  if (!Error)
2449  {
2450  /* NOTE: Name.string is not null-terminated */
2451  UNICODE_STRING Tmp;
2452  Tmp.Buffer = (PWCH)Name.string;
2453  Tmp.Length = Tmp.MaximumLength = Name.string_len;
2454 
2455  pNameW->Length = 0;
2456  pNameW->MaximumLength = Name.string_len + sizeof(WCHAR);
2458 
2459  if (pNameW->Buffer)
2460  {
2461  Status = RtlAppendUnicodeStringToString(pNameW, &Tmp);
2462  if (Status == STATUS_SUCCESS)
2463  {
2464  /* Convert UTF-16 big endian to little endian */
2465  SwapEndian(pNameW->Buffer, pNameW->Length);
2466  }
2467  }
2468  else
2469  {
2471  }
2472  }
2473  }
2474 
2475  if (!NT_SUCCESS(Status))
2476  {
2477  /* defaulted */
2478  if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
2479  {
2480  RtlInitAnsiString(&AnsiName, Face->style_name);
2481  Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2482  }
2483  else
2484  {
2485  RtlInitAnsiString(&AnsiName, Face->family_name);
2486  Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2487  }
2488  }
2489 
2490  if (NT_SUCCESS(Status))
2491  {
2492  /* make cache */
2493  if (NameID == TT_NAME_ID_FONT_FAMILY)
2494  {
2496  IntLockFreeType();
2497  if (!Cache->FontFamily.Buffer)
2498  DuplicateUnicodeString(pNameW, &Cache->FontFamily);
2500  }
2501  else if (NameID == TT_NAME_ID_FULL_NAME)
2502  {
2504  IntLockFreeType();
2505  if (!Cache->FullName.Buffer)
2506  DuplicateUnicodeString(pNameW, &Cache->FullName);
2508  }
2509  }
2510 
2511  return Status;
2512 }
2513 
2514 static void FASTCALL
2516  LPCWSTR FullName, PFONTGDI FontGDI)
2517 {
2518  ANSI_STRING StyleA;
2519  UNICODE_STRING StyleW;
2520  TT_OS2 *pOS2;
2521  FONTSIGNATURE fs;
2522  CHARSETINFO CharSetInfo;
2523  unsigned i, Size;
2524  OUTLINETEXTMETRICW *Otm;
2525  LOGFONTW *Lf;
2526  TEXTMETRICW *TM;
2527  NEWTEXTMETRICW *Ntm;
2528  DWORD fs0;
2529  NTSTATUS status;
2530  PSHARED_FACE SharedFace = FontGDI->SharedFace;
2531  FT_Face Face = SharedFace->Face;
2532  UNICODE_STRING NameW;
2533 
2534  RtlInitUnicodeString(&NameW, NULL);
2535  RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
2536  Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2538  if (!Otm)
2539  {
2540  return;
2541  }
2542  Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2543  if (!Size)
2544  {
2546  return;
2547  }
2548 
2549  Lf = &Info->EnumLogFontEx.elfLogFont;
2550  TM = &Otm->otmTextMetrics;
2551 
2552  Lf->lfHeight = TM->tmHeight;
2553  Lf->lfWidth = TM->tmAveCharWidth;
2554  Lf->lfWeight = TM->tmWeight;
2555  Lf->lfItalic = TM->tmItalic;
2556  Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
2557  Lf->lfCharSet = TM->tmCharSet;
2560  Lf->lfQuality = PROOF_QUALITY;
2561 
2562  Ntm = &Info->NewTextMetricEx.ntmTm;
2563  Ntm->tmHeight = TM->tmHeight;
2564  Ntm->tmAscent = TM->tmAscent;
2565  Ntm->tmDescent = TM->tmDescent;
2568  Ntm->tmAveCharWidth = TM->tmAveCharWidth;
2569  Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
2570  Ntm->tmWeight = TM->tmWeight;
2571  Ntm->tmOverhang = TM->tmOverhang;
2574  Ntm->tmFirstChar = TM->tmFirstChar;
2575  Ntm->tmLastChar = TM->tmLastChar;
2576  Ntm->tmDefaultChar = TM->tmDefaultChar;
2577  Ntm->tmBreakChar = TM->tmBreakChar;
2578  Ntm->tmItalic = TM->tmItalic;
2579  Ntm->tmUnderlined = TM->tmUnderlined;
2580  Ntm->tmStruckOut = TM->tmStruckOut;
2582  Ntm->tmCharSet = TM->tmCharSet;
2583  Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
2584 
2585  if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
2586 
2587  if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
2588 
2589  Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
2590  ? TRUETYPE_FONTTYPE : 0);
2591 
2592  if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
2593  Info->FontType |= RASTER_FONTTYPE;
2594 
2595 
2596  /* face name */
2597  if (!FaceName)
2598  FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
2599 
2600  RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
2601 
2602  /* full name */
2603  if (!FullName)
2604  FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName);
2605 
2607  sizeof(Info->EnumLogFontEx.elfFullName),
2608  FullName);
2609 
2610  RtlInitAnsiString(&StyleA, Face->style_name);
2611  StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
2612  StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
2613  status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
2614  if (!NT_SUCCESS(status))
2615  {
2617  return;
2618  }
2620 
2621  IntLockFreeType();
2622  pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2623 
2624  if (!pOS2)
2625  {
2628  return;
2629  }
2630 
2631  Ntm->ntmSizeEM = Otm->otmEMSquare;
2632  Ntm->ntmCellHeight = pOS2->usWinAscent + pOS2->usWinDescent;
2633  Ntm->ntmAvgWidth = 0;
2634 
2636 
2637  fs.fsCsb[0] = pOS2->ulCodePageRange1;
2638  fs.fsCsb[1] = pOS2->ulCodePageRange2;
2639  fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2640  fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2641  fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2642  fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2643 
2644  if (0 == pOS2->version)
2645  {
2646  FT_UInt Dummy;
2647 
2648  if (FT_Get_First_Char(Face, &Dummy) < 0x100)
2649  fs.fsCsb[0] |= FS_LATIN1;
2650  else
2651  fs.fsCsb[0] |= FS_SYMBOL;
2652  }
2654 
2655  if (fs.fsCsb[0] == 0)
2656  {
2657  /* Let's see if we can find any interesting cmaps */
2658  for (i = 0; i < (UINT)Face->num_charmaps; i++)
2659  {
2660  switch (Face->charmaps[i]->encoding)
2661  {
2662  case FT_ENCODING_UNICODE:
2663  case FT_ENCODING_APPLE_ROMAN:
2664  fs.fsCsb[0] |= FS_LATIN1;
2665  break;
2666  case FT_ENCODING_MS_SYMBOL:
2667  fs.fsCsb[0] |= FS_SYMBOL;
2668  break;
2669  default:
2670  break;
2671  }
2672  }
2673  }
2674 
2675  for (i = 0; i < MAXTCIINDEX; i++)
2676  {
2677  fs0 = 1L << i;
2678  if (fs.fsCsb[0] & fs0)
2679  {
2680  if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
2681  {
2682  CharSetInfo.ciCharset = DEFAULT_CHARSET;
2683  }
2684  if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
2685  {
2686  if (g_ElfScripts[i])
2688  else
2689  {
2690  DPRINT1("Unknown elfscript for bit %u\n", i);
2691  }
2692  }
2693  }
2694  }
2695  Info->NewTextMetricEx.ntmFontSig = fs;
2696 }
2697 
2698 static int FASTCALL
2700 {
2701  DWORD i;
2702  UNICODE_STRING InfoFaceName;
2703 
2704  for (i = 0; i < InfoEntries; i++)
2705  {
2706  RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
2707  if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE))
2708  {
2709  return i;
2710  }
2711  }
2712 
2713  return -1;
2714 }
2715 
2716 static BOOLEAN FASTCALL
2718  PFONTFAMILYINFO Info, DWORD InfoEntries)
2719 {
2720  UNICODE_STRING LogFontFaceName;
2721 
2722  RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
2723  if (0 != LogFontFaceName.Length &&
2724  !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE))
2725  {
2726  return FALSE;
2727  }
2728 
2729  return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
2730 }
2731 
2732 static BOOL FASTCALL
2734  PFONTFAMILYINFO Info, DWORD InfoCount)
2735 {
2736  LPLOGFONTW plf1 = &InfoEntry->EnumLogFontEx.elfLogFont;
2737  LPWSTR pFullName1 = InfoEntry->EnumLogFontEx.elfFullName;
2738  LPWSTR pFullName2;
2739  DWORD i;
2740 
2741  for (i = 0; i < InfoCount; ++i)
2742  {
2743  LPLOGFONTW plf2 = &Info[i].EnumLogFontEx.elfLogFont;
2744  if (plf1->lfCharSet != plf2->lfCharSet)
2745  continue;
2746 
2747  pFullName2 = Info[i].EnumLogFontEx.elfFullName;
2748  if (_wcsicmp(pFullName1, pFullName2) != 0)
2749  continue;
2750 
2751  return TRUE;
2752  }
2753  return FALSE;
2754 }
2755 
2756 static BOOLEAN FASTCALL
2759  DWORD *pCount,
2760  DWORD MaxCount,
2761  PLIST_ENTRY Head)
2762 {
2764  PFONT_ENTRY CurrentEntry;
2765  FONTGDI *FontGDI;
2766  FONTFAMILYINFO InfoEntry;
2767  DWORD Count = *pCount;
2768 
2769  for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
2770  {
2771  CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2772  FontGDI = CurrentEntry->Font;
2773  ASSERT(FontGDI);
2774 
2775  if (LogFont->lfCharSet != DEFAULT_CHARSET &&
2776  LogFont->lfCharSet != FontGDI->CharSet)
2777  {
2778  continue;
2779  }
2780 
2781  if (LogFont->lfFaceName[0] == UNICODE_NULL)
2782  {
2783  if (Count < MaxCount)
2784  {
2785  FontFamilyFillInfo(&Info[Count], NULL, NULL, FontGDI);
2786  }
2787  Count++;
2788  continue;
2789  }
2790 
2791  FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
2792 
2793  if (_wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0 &&
2794  _wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfFullName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0)
2795  {
2796  continue;
2797  }
2798 
2799  if (!FontFamilyFound(&InfoEntry, Info, min(Count, MaxCount)))
2800  {
2801  if (Count < MaxCount)
2802  {
2803  RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
2804  }
2805  Count++;
2806  }
2807  }
2808 
2809  *pCount = Count;
2810 
2811  return TRUE;
2812 }
2813 
2814 static BOOLEAN FASTCALL
2817  DWORD *pCount,
2818  DWORD MaxCount)
2819 {
2820  PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead;
2821  PFONTSUBST_ENTRY pCurrentEntry;
2822  PUNICODE_STRING pFromW;
2823  FONTGDI *FontGDI;
2824  LOGFONTW lf = *LogFont;
2825  UNICODE_STRING NameW;
2826 
2827  for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
2828  {
2829  pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
2830 
2831  pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
2832  if (LogFont->lfFaceName[0] != UNICODE_NULL)
2833  {
2834  if (!FontFamilyInclude(LogFont, pFromW, Info, min(*pCount, MaxCount)))
2835  continue; /* mismatch */
2836  }
2837 
2838  IntUnicodeStringToBuffer(lf.lfFaceName, sizeof(lf.lfFaceName), pFromW);
2839  SubstituteFontRecurse(&lf);
2840 
2841  RtlInitUnicodeString(&NameW, lf.lfFaceName);
2842  FontGDI = FindFaceNameInLists(&NameW);
2843  if (FontGDI == NULL)
2844  {
2845  continue; /* no real font */
2846  }
2847 
2848  if (*pCount < MaxCount)
2849  {
2850  FontFamilyFillInfo(&Info[*pCount], pFromW->Buffer, NULL, FontGDI);
2851  }
2852  (*pCount)++;
2853  }
2854 
2855  return TRUE;
2856 }
2857 
2858 BOOL
2859 FASTCALL
2861 {
2862  if ( lprs )
2863  {
2864  lprs->nSize = sizeof(RASTERIZER_STATUS);
2865  lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
2866  lprs->nLanguageID = gusLanguageID;
2867  return TRUE;
2868  }
2870  return FALSE;
2871 }
2872 
2873 static
2874 BOOL
2876  PMATRIX pmx1,
2877  PMATRIX pmx2)
2878 {
2879  return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
2880  FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
2881  FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
2882  FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
2883 }
2884 
2887  FT_Face Face,
2888  INT GlyphIndex,
2889  INT Height,
2890  FT_Render_Mode RenderMode,
2891  PMATRIX pmx)
2892 {
2893  PLIST_ENTRY CurrentEntry;
2894  PFONT_CACHE_ENTRY FontEntry;
2895 
2897 
2898  for (CurrentEntry = g_FontCacheListHead.Flink;
2899  CurrentEntry != &g_FontCacheListHead;
2900  CurrentEntry = CurrentEntry->Flink)
2901  {
2902  FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
2903  if ((FontEntry->Face == Face) &&
2904  (FontEntry->GlyphIndex == GlyphIndex) &&
2905  (FontEntry->Height == Height) &&
2906  (FontEntry->RenderMode == RenderMode) &&
2907  (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2908  break;
2909  }
2910 
2911  if (CurrentEntry == &g_FontCacheListHead)
2912  {
2913  return NULL;
2914  }
2915 
2916  RemoveEntryList(CurrentEntry);
2917  InsertHeadList(&g_FontCacheListHead, CurrentEntry);
2918  return FontEntry->BitmapGlyph;
2919 }
2920 
2921 /* no cache */
2924  FT_Face Face,
2925  FT_GlyphSlot GlyphSlot,
2926  FT_Render_Mode RenderMode)
2927 {
2928  FT_Glyph Glyph;
2929  INT error;
2930  FT_Bitmap AlignedBitmap;
2931  FT_BitmapGlyph BitmapGlyph;
2932 
2933  error = FT_Get_Glyph(GlyphSlot, &Glyph);
2934  if (error)
2935  {
2936  DPRINT1("Failure getting glyph.\n");
2937  return NULL;
2938  }
2939 
2940  error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2941  if (error)
2942  {
2943  FT_Done_Glyph(Glyph);
2944  DPRINT1("Failure rendering glyph.\n");
2945  return NULL;
2946  }
2947 
2948  BitmapGlyph = (FT_BitmapGlyph)Glyph;
2949  FT_Bitmap_New(&AlignedBitmap);
2950  if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2951  {
2952  DPRINT1("Conversion failed\n");
2953  FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2954  return NULL;
2955  }
2956 
2957  FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2958  BitmapGlyph->bitmap = AlignedBitmap;
2959 
2960  return BitmapGlyph;
2961 }
2962 
2965  FT_Face Face,
2966  INT GlyphIndex,
2967  INT Height,
2968  PMATRIX pmx,
2969  FT_GlyphSlot GlyphSlot,
2970  FT_Render_Mode RenderMode)
2971 {
2972  FT_Glyph GlyphCopy;
2973  INT error;
2974  PFONT_CACHE_ENTRY NewEntry;
2975  FT_Bitmap AlignedBitmap;
2976  FT_BitmapGlyph BitmapGlyph;
2977 
2979 
2980  error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2981  if (error)
2982  {
2983  DPRINT1("Failure caching glyph.\n");
2984  return NULL;
2985  };
2986 
2987  error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2988  if (error)
2989  {
2990  FT_Done_Glyph(GlyphCopy);
2991  DPRINT1("Failure rendering glyph.\n");
2992  return NULL;
2993  };
2994 
2996  if (!NewEntry)
2997  {
2998  DPRINT1("Alloc failure caching glyph.\n");
2999  FT_Done_Glyph(GlyphCopy);
3000  return NULL;
3001  }
3002 
3003  BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
3004  FT_Bitmap_New(&AlignedBitmap);
3005  if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
3006  {
3007  DPRINT1("Conversion failed\n");
3008  ExFreePoolWithTag(NewEntry, TAG_FONT);
3009  FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
3010  FT_Done_Glyph((FT_Glyph)BitmapGlyph);
3011  return NULL;
3012  }
3013 
3014  FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
3015  BitmapGlyph->bitmap = AlignedBitmap;
3016 
3017  NewEntry->GlyphIndex = GlyphIndex;
3018  NewEntry->Face = Face;
3019  NewEntry->BitmapGlyph = BitmapGlyph;
3020  NewEntry->Height = Height;
3021  NewEntry->RenderMode = RenderMode;
3022  NewEntry->mxWorldToDevice = *pmx;
3023 
3024  InsertHeadList(&g_FontCacheListHead, &NewEntry->ListEntry);
3026  {
3027  NewEntry = CONTAINING_RECORD(g_FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
3028  RemoveCachedEntry(NewEntry);
3029  }
3030 
3031  return BitmapGlyph;
3032 }
3033 
3034 
3036 {
3037  pt->x.value = vec->x >> 6;
3038  pt->x.fract = (vec->x & 0x3f) << 10;
3039  pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
3040  pt->y.value = vec->y >> 6;
3041  pt->y.fract = (vec->y & 0x3f) << 10;
3042  pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
3043 }
3044 
3045 /*
3046  This function builds an FT_Fixed from a float. It puts the integer part
3047  in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
3048  It fails if the integer part of the float number is greater than SHORT_MAX.
3049 */
3050 static __inline FT_Fixed FT_FixedFromFloat(float f)
3051 {
3052  short value = f;
3053  unsigned short fract = (f - value) * 0xFFFF;
3054  return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
3055 }
3056 
3057 /*
3058  This function builds an FT_Fixed from a FIXED. It simply put f.value
3059  in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
3060 */
3062 {
3063  return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
3064 }
3065 
3066 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3067 {
3068  TTPOLYGONHEADER *pph;
3069  TTPOLYCURVE *ppc;
3070  int needed = 0, point = 0, contour, first_pt;
3071  unsigned int pph_start, cpfx;
3072  DWORD type;
3073 
3074  for (contour = 0; contour < outline->n_contours; contour++)
3075  {
3076  /* Ignore contours containing one point */
3077  if (point == outline->contours[contour])
3078  {
3079  point++;
3080  continue;
3081  }
3082 
3083  pph_start = needed;
3084  pph = (TTPOLYGONHEADER *)(buf + needed);
3085  first_pt = point;
3086  if (buf)
3087  {
3088  pph->dwType = TT_POLYGON_TYPE;
3089  FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3090  }
3091  needed += sizeof(*pph);
3092  point++;
3093  while (point <= outline->contours[contour])
3094  {
3095  ppc = (TTPOLYCURVE *)(buf + needed);
3096  type = outline->tags[point] & FT_Curve_Tag_On ?
3098  cpfx = 0;
3099  do
3100  {
3101  if (buf)
3102  FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3103  cpfx++;
3104  point++;
3105  } while (point <= outline->contours[contour] &&
3106  (outline->tags[point] & FT_Curve_Tag_On) ==
3107  (outline->tags[point-1] & FT_Curve_Tag_On));
3108  /* At the end of a contour Windows adds the start point, but
3109  only for Beziers */
3110  if (point > outline->contours[contour] &&
3111  !(outline->tags[point-1] & FT_Curve_Tag_On))
3112  {
3113  if (buf)
3114  FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3115  cpfx++;
3116  }
3117  else if (point <= outline->contours[contour] &&
3118  outline->tags[point] & FT_Curve_Tag_On)
3119  {
3120  /* add closing pt for bezier */
3121  if (buf)
3122  FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3123  cpfx++;
3124  point++;
3125  }
3126  if (buf)
3127  {
3128  ppc->wType = type;
3129  ppc->cpfx = cpfx;
3130  }
3131  needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3132  }
3133  if (buf)
3134  pph->cb = needed - pph_start;
3135  }
3136  return needed;
3137 }
3138 
3139 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3140 {
3141  /* Convert the quadratic Beziers to cubic Beziers.
3142  The parametric eqn for a cubic Bezier is, from PLRM:
3143  r(t) = at^3 + bt^2 + ct + r0
3144  with the control points:
3145  r1 = r0 + c/3
3146  r2 = r1 + (c + b)/3
3147  r3 = r0 + c + b + a
3148 
3149  A quadratic Bezier has the form:
3150  p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3151 
3152  So equating powers of t leads to:
3153  r1 = 2/3 p1 + 1/3 p0
3154  r2 = 2/3 p1 + 1/3 p2
3155  and of course r0 = p0, r3 = p2
3156  */
3157  int contour, point = 0, first_pt;
3158  TTPOLYGONHEADER *pph;
3159  TTPOLYCURVE *ppc;
3160  DWORD pph_start, cpfx, type;
3161  FT_Vector cubic_control[4];
3162  unsigned int needed = 0;
3163 
3164  for (contour = 0; contour < outline->n_contours; contour++)
3165  {
3166  pph_start = needed;
3167  pph = (TTPOLYGONHEADER *)(buf + needed);
3168  first_pt = point;
3169  if (buf)
3170  {
3171  pph->dwType = TT_POLYGON_TYPE;
3172  FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3173  }
3174  needed += sizeof(*pph);
3175  point++;
3176  while (point <= outline->contours[contour])
3177  {
3178  ppc = (TTPOLYCURVE *)(buf + needed);
3179  type = outline->tags[point] & FT_Curve_Tag_On ?
3181  cpfx = 0;
3182  do
3183  {
3184  if (type == TT_PRIM_LINE)
3185  {
3186  if (buf)
3187  FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3188  cpfx++;
3189  point++;
3190  }
3191  else
3192  {
3193  /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3194  so cpfx = 3n */
3195 
3196  /* FIXME: Possible optimization in endpoint calculation
3197  if there are two consecutive curves */
3198  cubic_control[0] = outline->points[point-1];
3199  if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3200  {
3201  cubic_control[0].x += outline->points[point].x + 1;
3202  cubic_control[0].y += outline->points[point].y + 1;
3203  cubic_control[0].x >>= 1;
3204  cubic_control[0].y >>= 1;
3205  }
3206  if (point+1 > outline->contours[contour])
3207  cubic_control[3] = outline->points[first_pt];
3208  else
3209  {
3210  cubic_control[3] = outline->points[point+1];
3211  if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3212  {
3213  cubic_control[3].x += outline->points[point].x + 1;
3214  cubic_control[3].y += outline->points[point].y + 1;
3215  cubic_control[3].x >>= 1;
3216  cubic_control[3].y >>= 1;
3217  }
3218  }
3219  /* r1 = 1/3 p0 + 2/3 p1
3220  r2 = 1/3 p2 + 2/3 p1 */
3221  cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3222  cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3223  cubic_control[2] = cubic_control[1];
3224  cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3225  cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3226  cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3227  cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3228  if (buf)
3229  {
3230  FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3231  FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3232  FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3233  }
3234  cpfx += 3;
3235  point++;
3236  }
3237  } while (point <= outline->contours[contour] &&
3238  (outline->tags[point] & FT_Curve_Tag_On) ==
3239  (outline->tags[point-1] & FT_Curve_Tag_On));
3240  /* At the end of a contour Windows adds the start point,
3241  but only for Beziers and we've already done that.
3242  */
3243  if (point <= outline->contours[contour] &&
3244  outline->tags[point] & FT_Curve_Tag_On)
3245  {
3246  /* This is the closing pt of a bezier, but we've already
3247  added it, so just inc point and carry on */
3248  point++;
3249  }
3250  if (buf)
3251  {
3252  ppc->wType = type;
3253  ppc->cpfx = cpfx;
3254  }
3255  needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3256  }
3257  if (buf)
3258  pph->cb = needed - pph_start;
3259  }
3260  return needed;
3261 }
3262 
3263 static FT_Error
3264 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
3265 {
3266  FT_Error error;
3267  FT_Size_RequestRec req;
3268  FT_Face face = FontGDI->SharedFace->Face;
3269  TT_OS2 *pOS2;
3270  TT_HoriHeader *pHori;
3271  FT_WinFNT_HeaderRec WinFNT;
3272  LONG Ascent, Descent, Sum, EmHeight64;
3273 
3274  lfWidth = abs(lfWidth);
3275  if (lfHeight == 0)
3276  {
3277  if (lfWidth == 0)
3278  {
3279  DPRINT("lfHeight and lfWidth are zero.\n");
3280  lfHeight = -16;
3281  }
3282  else
3283  {
3284  lfHeight = lfWidth;
3285  }
3286  }
3287 
3288  if (lfHeight == -1)
3289  lfHeight = -2;
3290 
3292  pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
3293  pHori = (TT_HoriHeader *)FT_Get_Sfnt_Table(face, FT_SFNT_HHEA);
3294 
3295  if (!pOS2 || !pHori)
3296  {
3297  error = FT_Get_WinFNT_Header(face, &WinFNT);
3298  if (error)
3299  {
3300  DPRINT1("%s: Failed to request font size.\n", face->family_name);
3301  ASSERT(FALSE);
3302  return error;
3303  }
3304 
3305  FontGDI->tmHeight = WinFNT.pixel_height;
3306  FontGDI->tmAscent = WinFNT.ascent;
3307  FontGDI->tmDescent = FontGDI->tmHeight - FontGDI->tmAscent;
3308  FontGDI->tmInternalLeading = WinFNT.internal_leading;
3309  FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3310  FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3311  FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3312  FontGDI->Magic = FONTGDI_MAGIC;
3313 
3315  req.width = 0;
3316  req.height = (FT_Long)(FontGDI->EmHeight << 6);
3317  req.horiResolution = 0;
3318  req.vertResolution = 0;
3319  return FT_Request_Size(face, &req);
3320  }
3321 
3322  /* See also: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fsselection */
3323 #define FM_SEL_USE_TYPO_METRICS 0x80
3324  if (lfHeight > 0)
3325  {
3326  /* case (A): lfHeight is positive */
3327  Sum = pOS2->usWinAscent + pOS2->usWinDescent;
3328  if (Sum == 0 || (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS))
3329  {
3330  Ascent = pHori->Ascender;
3331  Descent = -pHori->Descender;
3332  Sum = Ascent + Descent;
3333  }
3334  else
3335  {
3336  Ascent = pOS2->usWinAscent;
3337  Descent = pOS2->usWinDescent;
3338  }
3339 
3340  FontGDI->tmAscent = FT_MulDiv(lfHeight, Ascent, Sum);
3341  FontGDI->tmDescent = FT_MulDiv(lfHeight, Descent, Sum);
3342  FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3343  FontGDI->tmInternalLeading = FontGDI->tmHeight - FT_MulDiv(lfHeight, face->units_per_EM, Sum);
3344  }
3345  else if (lfHeight < 0)
3346  {
3347  /* case (B): lfHeight is negative */
3349  {
3350  FontGDI->tmAscent = FT_MulDiv(-lfHeight, pHori->Ascender, face->units_per_EM);
3351  FontGDI->tmDescent = FT_MulDiv(-lfHeight, -pHori->Descender, face->units_per_EM);
3352  }
3353  else
3354  {
3355  FontGDI->tmAscent = FT_MulDiv(-lfHeight, pOS2->usWinAscent, face->units_per_EM);
3356  FontGDI->tmDescent = FT_MulDiv(-lfHeight, pOS2->usWinDescent, face->units_per_EM);
3357  }
3358  FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3359  FontGDI->tmInternalLeading = FontGDI->tmHeight + lfHeight;
3360  }
3361 #undef FM_SEL_USE_TYPO_METRICS
3362 
3363  FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3364  FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3365  FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3366  FontGDI->Magic = FONTGDI_MAGIC;
3367 
3368  if (lfHeight > 0)
3369  EmHeight64 = (FontGDI->EmHeight << 6) + 31;
3370  else
3371  EmHeight64 = (FontGDI->EmHeight << 6);
3372 
3374  req.width = 0;
3375  req.height = EmHeight64;
3376  req.horiResolution = 0;
3377  req.vertResolution = 0;
3378  return FT_Request_Size(face, &req);
3379 }
3380 
3381 BOOL
3382 FASTCALL
3384  PTEXTOBJ TextObj,
3385  PFONTGDI FontGDI,
3386  BOOL bDoLock)
3387 {
3388  FT_Face face;
3389  INT error, n;
3390  FT_CharMap charmap, found;
3391  LOGFONTW *plf;
3392 
3393  if (bDoLock)
3394  IntLockFreeType();
3395 
3396  face = FontGDI->SharedFace->Face;
3397  if (face->charmap == NULL)
3398  {
3399  DPRINT("WARNING: No charmap selected!\n");
3400  DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3401 
3402  found = NULL;
3403  for (n = 0; n < face->num_charmaps; n++)
3404  {
3405  charmap = face->charmaps[n];
3406  if (charmap->encoding == FT_ENCODING_UNICODE)
3407  {
3408  found = charmap;
3409  break;
3410  }
3411  }
3412  if (!found)
3413  {
3414  for (n = 0; n < face->num_charmaps; n++)
3415  {
3416  charmap = face->charmaps[n];
3417  if (charmap->encoding == FT_ENCODING_MS_SYMBOL)
3418  {
3419  found = charmap;
3420  break;
3421  }
3422  }
3423  }
3424  if (!found)
3425  {
3426  DPRINT1("WARNING: Could not find desired charmap!\n");
3427  }
3428  else
3429  {
3430  DPRINT("Found charmap encoding: %i\n", found->encoding);
3431  error = FT_Set_Charmap(face, found);
3432  if (error)
3433  {
3434  DPRINT1("WARNING: Could not set the charmap!\n");
3435  }
3436  }
3437  }
3438 
3439  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3440 
3441  error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
3442 
3443  if (bDoLock)
3445 
3446  if (error)
3447  {
3448  DPRINT1("Error in setting pixel sizes: %d\n", error);
3449  return FALSE;
3450  }
3451 
3452  return TRUE;
3453 }
3454 
3455 static inline FT_UInt FASTCALL
3457 {
3458  FT_UInt ret;
3459 
3460  if (glyph < 0x100) glyph += 0xf000;
3461  /* there are a number of old pre-Unicode "broken" TTFs, which
3462  do have symbols at U+00XX instead of U+f0XX */
3463  if (!(ret = FT_Get_Char_Index(ft_face, glyph)))
3464  ret = FT_Get_Char_Index(ft_face, glyph - 0xf000);
3465 
3466  return ret;
3467 }
3468 
3469 static inline FT_UInt FASTCALL
3471 {
3472  FT_UInt ret;
3473 
3474  if (face_has_symbol_charmap(ft_face))
3475  {
3476  ret = get_glyph_index_symbol(ft_face, glyph);
3477  if (ret != 0)
3478  return ret;
3479  }
3480 
3481  return FT_Get_Char_Index(ft_face, glyph);
3482 }
3483 
3484 static inline FT_UInt FASTCALL
3486 {
3487  FT_UInt glyph_index;
3488  if (flags & indexed_flag)
3489  {
3490  glyph_index = code;
3491  }
3492  else
3493  {
3494  glyph_index = get_glyph_index(face, code);
3495  }
3496  return glyph_index;
3497 }
3498 
3499 /*
3500  * Based on WineEngGetGlyphOutline
3501  *
3502  */
3503 ULONG
3504 FASTCALL
3506  PDC dc,
3507  WCHAR wch,
3508  UINT iFormat,
3509  LPGLYPHMETRICS pgm,
3510  ULONG cjBuf,
3511  PVOID pvBuf,
3512  LPMAT2 pmat2,
3513  BOOL bIgnoreRotation)
3514 {
3515  static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3516  PDC_ATTR pdcattr;
3517  PTEXTOBJ TextObj;
3518  PFONTGDI FontGDI;
3519  HFONT hFont = 0;
3520  GLYPHMETRICS gm;
3521  ULONG Size;
3522  FT_Face ft_face;
3523  FT_UInt glyph_index;
3524  DWORD width, height, pitch, needed = 0;
3525  FT_Bitmap ft_bitmap;
3526  FT_Error error;
3527  INT left, right, top = 0, bottom = 0;
3528  FT_Angle angle = 0;
3530  FLOAT eM11, widthRatio = 1.0;
3531  FT_Matrix transMat = identityMat;
3532  BOOL needsTransform = FALSE;
3533  INT orientation;
3534  LONG aveWidth;
3535  INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3536  OUTLINETEXTMETRICW *potm;
3537  XFORM xForm;
3538  LOGFONTW *plf;
3539 
3540  DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3541  cjBuf, pvBuf, pmat2);
3542 
3543  pdcattr = dc->pdcattr;
3544 
3545  MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
3546  eM11 = xForm.eM11;
3547 
3548  hFont = pdcattr->hlfntNew;
3549  TextObj = RealizeFontInit(hFont);
3550 
3551  if (!TextObj)
3552  {
3554  return GDI_ERROR;
3555  }
3556  FontGDI = ObjToGDI(TextObj->Font, FONT);
3557  ft_face = FontGDI->SharedFace->Face;
3558 
3559  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3560  aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3561  orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3562 
3563  Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3565  if (!potm)
3566  {
3568  TEXTOBJ_UnlockText(TextObj);
3569  return GDI_ERROR;
3570  }
3571  Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
3572  if (!Size)
3573  {
3574  /* FIXME: last error? */
3576  TEXTOBJ_UnlockText(TextObj);
3577  return GDI_ERROR;
3578  }
3579 
3580  IntLockFreeType();
3581  TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3583 
3584  TEXTOBJ_UnlockText(TextObj);
3585 
3586  glyph_index = get_glyph_index_flagged(ft_face, wch, GGO_GLYPH_INDEX, iFormat);
3587  iFormat &= ~GGO_GLYPH_INDEX;
3588 
3589  if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3590  load_flags |= FT_LOAD_NO_BITMAP;
3591 
3592  if (iFormat & GGO_UNHINTED)
3593  {
3594  load_flags |= FT_LOAD_NO_HINTING;
3595  iFormat &= ~GGO_UNHINTED;
3596  }
3597 
3598  error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3599  if (error)
3600  {
3601  DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3603  if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3604  return GDI_ERROR;
3605  }
3607 
3608  if (aveWidth && potm)
3609  {
3610  widthRatio = (FLOAT)aveWidth * eM11 /
3612  }
3613 
3614  left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3615  right = (INT)((ft_face->glyph->metrics.horiBearingX +
3616  ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3617 
3618  adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3619  lsb = left >> 6;
3620  bbx = (right - left) >> 6;
3621 
3622  DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3623 
3624  IntLockFreeType();
3625 
3626  /* Width scaling transform */
3627  if (widthRatio != 1.0)
3628  {
3629  FT_Matrix scaleMat;
3630  scaleMat.xx = FT_FixedFromFloat(widthRatio);
3631  scaleMat.xy = 0;
3632  scaleMat.yx = 0;
3633  scaleMat.yy = FT_FixedFromFloat(1.0);
3634 
3635  FT_Matrix_Multiply(&scaleMat, &transMat);
3636  needsTransform = TRUE;
3637  }
3638 
3639  /* World transform */
3640  {
3641  FT_Matrix ftmatrix;
3642  FLOATOBJ efTemp;
3643  PMATRIX pmx = DC_pmxWorldToDevice(dc);
3644 
3645  /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3646  efTemp = pmx->efM11;
3647  FLOATOBJ_MulLong(&efTemp, 0x00010000);
3648  ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
3649 
3650  efTemp = pmx->efM12;
3651  FLOATOBJ_MulLong(&efTemp, 0x00010000);
3652  ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
3653 
3654  efTemp = pmx->efM21;
3655  FLOATOBJ_MulLong(&efTemp, 0x00010000);
3656  ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
3657 
3658  efTemp = pmx->efM22;
3659  FLOATOBJ_MulLong(&efTemp, 0x00010000);
3660  ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
3661 
3662  if (memcmp(&ftmatrix, &identityMat, sizeof(identityMat)) != 0)
3663  {
3664  FT_Matrix_Multiply(&ftmatrix, &transMat);
3665  needsTransform = TRUE;
3666  }
3667  }
3668 
3669  /* Rotation transform */
3670  if (orientation)
3671  {
3672  FT_Matrix rotationMat;
3673  FT_Vector vecAngle;
3674  DPRINT("Rotation Trans!\n");
3675  angle = FT_FixedFromFloat((float)orientation / 10.0);
3676  FT_Vector_Unit(&vecAngle, angle);
3677  rotationMat.xx = vecAngle.x;
3678  rotationMat.xy = -vecAngle.y;
3679  rotationMat.yx = -rotationMat.xy;
3680  rotationMat.yy = rotationMat.xx;
3681  FT_Matrix_Multiply(&rotationMat, &transMat);
3682  needsTransform = TRUE;
3683  }
3684 
3685  /* Extra transformation specified by caller */
3686  if (pmat2)
3687  {
3688  FT_Matrix extraMat;
3689  DPRINT("MAT2 Matrix Trans!\n");
3690  extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
3691  extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
3692  extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
3693  extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
3694  FT_Matrix_Multiply(&extraMat, &transMat);
3695  needsTransform = TRUE;
3696  }
3697 
3698  if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
3699 
3700  if (!needsTransform)
3701  {
3702  DPRINT("No Need to be Transformed!\n");
3703  top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3704  bottom = (ft_face->glyph->metrics.horiBearingY -
3705  ft_face->glyph->metrics.height) & -64;
3706  gm.gmCellIncX = adv;
3707  gm.gmCellIncY = 0;
3708  }
3709  else
3710  {
3711  INT xc, yc;
3712  FT_Vector vec;
3713  for (xc = 0; xc < 2; xc++)
3714  {
3715  for (yc = 0; yc < 2; yc++)
3716  {
3717  vec.x = (ft_face->glyph->metrics.horiBearingX +
3718  xc * ft_face->glyph->metrics.width);
3719  vec.y = ft_face->glyph->metrics.horiBearingY -
3720  yc * ft_face->glyph->metrics.height;
3721  DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
3722  FT_Vector_Transform(&vec, &transMat);
3723  if (xc == 0 && yc == 0)
3724  {
3725  left = right = vec.x;
3726  top = bottom = vec.y;
3727  }
3728  else
3729  {
3730  if (vec.x < left) left = vec.x;
3731  else if (vec.x > right) right = vec.x;
3732  if (vec.y < bottom) bottom = vec.y;
3733  else if (vec.y > top) top = vec.y;
3734  }
3735  }
3736  }
3737  left = left & -64;
3738  right = (right + 63) & -64;
3739  bottom = bottom & -64;
3740  top = (top + 63) & -64;
3741 
3742  DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3743  vec.x = ft_face->glyph->metrics.horiAdvance;
3744  vec.y = 0;
3745  FT_Vector_Transform(&vec, &transMat);
3746  gm.gmCellIncX = (vec.x+63) >> 6;
3747  gm.gmCellIncY = -((vec.y+63) >> 6);
3748  }
3749  gm.gmBlackBoxX = (right - left) >> 6;
3750  gm.gmBlackBoxY = (top - bottom) >> 6;
3751  gm.gmptGlyphOrigin.x = left >> 6;
3752  gm.gmptGlyphOrigin.y = top >> 6;
3753 
3754  DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
3755  gm.gmCellIncX, gm.gmCellIncY,
3756  gm.gmBlackBoxX, gm.gmBlackBoxY,
3758 
3760 
3761 
3762  if (iFormat == GGO_METRICS)
3763  {
3764  DPRINT("GGO_METRICS Exit!\n");
3765  *pgm = gm;
3766  return 1; /* FIXME */
3767  }
3768 
3769  if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
3770  {
3771  DPRINT1("Loaded a bitmap\n");
3772  return GDI_ERROR;
3773  }
3774 
3775  switch (iFormat)
3776  {
3777  case GGO_BITMAP:
3778  width = gm.gmBlackBoxX;
3779  height = gm.gmBlackBoxY;
3780  pitch = ((width + 31) >> 5) << 2;
3781  needed = pitch * height;
3782 
3783  if (!pvBuf || !cjBuf) break;
3784  if (!needed) return GDI_ERROR; /* empty glyph */
3785  if (needed > cjBuf)
3786  return GDI_ERROR;
3787 
3788  switch (ft_face->glyph->format)
3789  {
3791  {
3792  BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3793  INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
3794  INT h = min( height, ft_face->glyph->bitmap.rows );
3795  while (h--)
3796  {
3797  RtlCopyMemory(dst, src, w);
3798  src += ft_face->glyph->bitmap.pitch;
3799  dst += pitch;
3800  }
3801  break;
3802  }
3803 
3805  ft_bitmap.width = width;
3806  ft_bitmap.rows = height;
3807  ft_bitmap.pitch = pitch;
3808  ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
3809  ft_bitmap.buffer = pvBuf;
3810 
3811  IntLockFreeType();
3812  if (needsTransform)
3813  {
3814  FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3815  }
3816  FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3817  /* Note: FreeType will only set 'black' bits for us. */
3818  RtlZeroMemory(pvBuf, needed);
3819  FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
3821  break;
3822 
3823  default:
3824  DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3825  return GDI_ERROR;
3826  }
3827  break;
3828 
3829  case GGO_GRAY2_BITMAP:
3830  case GGO_GRAY4_BITMAP:
3831  case GGO_GRAY8_BITMAP:
3832  {
3833  unsigned int mult, row, col;
3834  BYTE *start, *ptr;
3835 
3836  width = gm.gmBlackBoxX;
3837  height = gm.gmBlackBoxY;
3838  pitch = (width + 3) / 4 * 4;
3839  needed = pitch * height;
3840 
3841  if (!pvBuf || !cjBuf) break;
3842  if (!needed) return GDI_ERROR; /* empty glyph */
3843  if (needed > cjBuf)
3844  return GDI_ERROR;
3845 
3846  switch (ft_face->glyph->format)
3847  {
3849  {
3850  BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3851  INT h = min( height, ft_face->glyph->bitmap.rows );
3852  INT x;
3853  while (h--)
3854  {
3855  for (x = 0; (UINT)x < pitch; x++)
3856  {
3857  if (x < ft_face->glyph->bitmap.width)
3858  dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3859  else
3860  dst[x] = 0;
3861  }
3862  src += ft_face->glyph->bitmap.pitch;
3863  dst += pitch;
3864  }
3865  break;
3866  }
3868  {
3869  ft_bitmap.width = width;
3870  ft_bitmap.rows = height;
3871  ft_bitmap.pitch = pitch;
3872  ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3873  ft_bitmap.buffer = pvBuf;
3874 
3875  IntLockFreeType();
3876  if (needsTransform)
3877  {
3878  FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3879  }
3880  FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3881  RtlZeroMemory(ft_bitmap.buffer, cjBuf);
3882  FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
3884 
3885  if (iFormat == GGO_GRAY2_BITMAP)
3886  mult = 4;
3887  else if (iFormat == GGO_GRAY4_BITMAP)
3888  mult = 16;
3889  else if (iFormat == GGO_GRAY8_BITMAP)
3890  mult = 64;
3891  else
3892  {
3893  return GDI_ERROR;
3894  }
3895 
3896  start = pvBuf;
3897  for (row = 0; row < height; row++)
3898  {
3899  ptr = start;
3900  for (col = 0; col < width; col++, ptr++)
3901  {
3902  *ptr = (((int)*ptr) * mult + 128) / 256;
3903  }
3904  start += pitch;
3905  }
3906 
3907  break;
3908  }
3909  default:
3910  DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3911  return GDI_ERROR;
3912  }
3913  }
3914 
3915  case GGO_NATIVE:
3916  {
3917  FT_Outline *outline = &ft_face->glyph->outline;
3918 
3919  if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
3920 
3921  IntLockFreeType();
3922  if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
3923 
3924  needed = get_native_glyph_outline(outline, cjBuf, NULL);
3925 
3926  if (!pvBuf || !cjBuf)
3927  {
3929  break;
3930  }
3931  if (needed > cjBuf)
3932  {
3934  return GDI_ERROR;
3935  }
3936  get_native_glyph_outline(outline, cjBuf, pvBuf);
3938  break;
3939  }
3940  case GGO_BEZIER:
3941  {
3942  FT_Outline *outline = &ft_face->glyph->outline;
3943  if (cjBuf == 0) pvBuf = NULL;
3944 
3945  if (needsTransform && pvBuf)
3946  {
3947  IntLockFreeType();
3948  FT_Outline_Transform(outline, &transMat);
3950  }
3951  needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
3952 
3953  if (!pvBuf || !cjBuf)
3954  break;
3955  if (needed > cjBuf)
3956  return GDI_ERROR;
3957 
3958  get_bezier_glyph_outline(outline, cjBuf, pvBuf);
3959  break;
3960  }
3961 
3962  default:
3963  DPRINT1("Unsupported format %u\n", iFormat);
3964  return GDI_ERROR;
3965  }
3966 
3967  DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
3968  *pgm = gm;
3969  return needed;
3970 }
3971 
3972 BOOL
3973 FASTCALL
3975  PTEXTOBJ TextObj,
3976  LPCWSTR String,
3977  INT Count,
3978  ULONG MaxExtent,
3979  LPINT Fit,
3980  LPINT Dx,
3981  LPSIZE Size,
3982  FLONG fl)
3983 {
3984  PFONTGDI FontGDI;
3985  FT_Face face;
3986  FT_GlyphSlot glyph;
3987  FT_BitmapGlyph realglyph;
3988  INT error, glyph_index, i, previous;
3989  ULONGLONG TotalWidth = 0;
3990  BOOL use_kerning;
3991  FT_Render_Mode RenderMode;
3992  BOOLEAN Render;
3993  PMATRIX pmxWorldToDevice;
3994  LOGFONTW *plf;
3995  BOOL EmuBold, EmuItalic;
3996  LONG ascender, descender;
3997 
3998  FontGDI = ObjToGDI(TextObj->Font, FONT);
3999 
4000  face = FontGDI->SharedFace->Face;
4001  if (NULL != Fit)
4002  {
4003  *Fit = 0;
4004  }
4005 
4006  IntLockFreeType();
4007 
4008  TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
4009 
4010  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4011  EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
4012  EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
4013 
4014  Render = IntIsFontRenderingEnabled();
4015  if (Render)
4016  RenderMode = IntGetFontRenderMode(plf);
4017  else
4018  RenderMode = FT_RENDER_MODE_MONO;
4019 
4020  /* Get the DC's world-to-device transformation matrix */
4021  pmxWorldToDevice = DC_pmxWorldToDevice(dc);
4022  FtSetCoordinateTransform(face, pmxWorldToDevice);
4023 
4024  use_kerning = FT_HAS_KERNING(face);
4025  previous = 0;
4026 
4027  for (i = 0; i < Count; i++)
4028  {
4029  glyph_index = get_glyph_index_flagged(face, *String, GTEF_INDICES, fl);
4030 
4031  if (EmuBold || EmuItalic)
4032  realglyph = NULL;
4033  else
4034  realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
4035  RenderMode, pmxWorldToDevice);
4036 
4037  if (EmuBold || EmuItalic || !realglyph)
4038  {
4039  error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
4040  if (error)
4041  {
4042  DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
4043  break;
4044  }
4045 
4046  glyph = face->glyph;
4047  if (EmuBold || EmuItalic)
4048  {
4049  if (EmuBold)
4050  FT_GlyphSlot_Embolden(glyph);
4051  if (EmuItalic)
4052  FT_GlyphSlot_Oblique(glyph);
4053  realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
4054  }
4055  else
4056  {
4057  realglyph = ftGdiGlyphCacheSet(face,
4058  glyph_index,
4059  plf->lfHeight,
4060  pmxWorldToDevice,
4061  glyph,
4062  RenderMode);
4063  }
4064 
4065  if (!realglyph)
4066  {
4067  DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
4068  break;
4069  }
4070  }
4071 
4072  /* Retrieve kerning distance */
4073  if (use_kerning && previous && glyph_index)
4074  {
4075  FT_Vector delta;
4076  FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
4077  TotalWidth += delta.x;
4078  }
4079 
4080  TotalWidth += realglyph->root.advance.x >> 10;
4081 
4082  if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
4083  {
4084  *Fit = i + 1;
4085  }
4086  if (NULL != Dx)
4087  {
4088  Dx[i] = (TotalWidth + 32) >> 6;
4089  }
4090 
4091  if (EmuBold || EmuItalic)
4092  {
4093  FT_Done_Glyph((FT_Glyph)realglyph);
4094  realglyph = NULL;
4095  }
4096 
4097  previous = glyph_index;
4098  String++;
4099  }
4100  ASSERT(FontGDI->Magic == FONTGDI_MAGIC);
4101  ascender = FontGDI->tmAscent; /* Units above baseline */
4102  descender = FontGDI->tmDescent; /* Units below baseline */
4104 
4105  Size->cx = (TotalWidth + 32) >> 6;
4106  Size->cy = ascender + descender;
4107 
4108  return TRUE;
4109 }
4110 
4111 
4112 INT
4113 FASTCALL
4115  PDC Dc,
4116  LPFONTSIGNATURE lpSig,
4117  DWORD dwFlags)
4118 {
4119  PDC_ATTR pdcattr;
4120  UINT Ret = DEFAULT_CHARSET;
4121  INT i;
4122  HFONT hFont;
4123  PTEXTOBJ TextObj;
4124  PFONTGDI FontGdi;
4125  FONTSIGNATURE fs;
4126  TT_OS2 *pOS2;
4127  FT_Face Face;
4128  CHARSETINFO csi;
4129  DWORD cp, fs0;
4130  USHORT usACP, usOEM;
4131 
4132  pdcattr = Dc->pdcattr;
4133  hFont = pdcattr->hlfntNew;
4134  TextObj = RealizeFontInit(hFont);
4135 
4136  if (!TextObj)
4137  {
4139  return Ret;
4140  }
4141  FontGdi = ObjToGDI(TextObj->Font, FONT);
4142  Face = FontGdi->SharedFace->Face;
4143  TEXTOBJ_UnlockText(TextObj);
4144 
4145  IntLockFreeType();
4146  pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4148  memset(&fs, 0, sizeof(FONTSIGNATURE));
4149  if (NULL != pOS2)
4150  {
4151  fs.fsCsb[0] = pOS2->ulCodePageRange1;
4152  fs.fsCsb[1] = pOS2->ulCodePageRange2;
4153  fs.fsUsb[0] = pOS2->ulUnicodeRange1;
4154  fs.fsUsb[1] = pOS2->ulUnicodeRange2;
4155  fs.fsUsb[2] = pOS2->ulUnicodeRange3;
4156  fs.fsUsb[3] = pOS2->ulUnicodeRange4;
4157  if (pOS2->version == 0)
4158  {
4159  FT_UInt dummy;
4160 
4161  if (FT_Get_First_Char( Face, &dummy ) < 0x100)
4162  fs.fsCsb[0] |= FS_LATIN1;
4163  else
4164  fs.fsCsb[0] |= FS_SYMBOL;
4165  }
4166  }
4167  DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
4168  if (fs.fsCsb[0] == 0)
4169  { /* Let's see if we can find any interesting cmaps */
4170  for (i = 0; i < Face->num_charmaps; i++)
4171  {
4172  switch (Face->charmaps[i]->encoding)
4173  {
4174  case FT_ENCODING_UNICODE:
4175  case FT_ENCODING_APPLE_ROMAN:
4176  fs.fsCsb[0] |= FS_LATIN1;
4177  break;
4178  case FT_ENCODING_MS_SYMBOL:
4179  fs.fsCsb[0] |= FS_SYMBOL;
4180  break;
4181  default:
4182  break;
4183  }
4184  }
4185  }
4186  if (lpSig)
4187  {
4188  RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
4189  }
4190 
4191  RtlGetDefaultCodePage(&usACP, &usOEM);
4192  cp = usACP;
4193 
4194  if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
4195  if (csi.fs.fsCsb[0] & fs.fsCsb[0])
4196  {
4197  DPRINT("Hit 1\n");
4198  Ret = csi.ciCharset;
4199  goto Exit;
4200  }
4201 
4202  for (i = 0; i < MAXTCIINDEX; i++)
4203  {
4204  fs0 = 1L << i;
4205  if (fs.fsCsb[0] & fs0)
4206  {
4207  if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
4208  {
4209  // *cp = csi.ciACP;
4210  DPRINT("Hit 2\n");
4211  Ret = csi.ciCharset;
4212  goto Exit;
4213  }
4214  else
4215  DPRINT1("TCI failing on %x\n", fs0);
4216  }
4217  }
4218 Exit:
4219  DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
4220  return (MAKELONG(csi.ciACP, csi.ciCharset));
4221 }
4222 
4223 
4224 DWORD
4225 FASTCALL
4227 {
4228  DWORD size = 0;
4229  DWORD num_ranges = 0;
4230  FT_Face face = Font->SharedFace->Face;
4231 
4232  if (face->charmap->encoding == FT_ENCODING_UNICODE)
4233  {
4234  FT_UInt glyph_code = 0;
4235  FT_ULong char_code, char_code_prev;
4236 
4237  char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
4238 
4239  DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4240  face->num_glyphs, glyph_code, char_code);
4241 
4242  if (!glyph_code) return 0;
4243 
4244  if (glyphset)
4245  {
4246  glyphset->ranges[0].wcLow = (USHORT)char_code;
4247  glyphset->ranges[0].cGlyphs = 0;
4248  glyphset->cGlyphsSupported = 0;
4249  }
4250 
4251  num_ranges = 1;
4252  while (glyph_code)
4253  {
4254  if (char_code < char_code_prev)
4255  {
4256  DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
4257  return 0;
4258  }
4259  if (char_code - char_code_prev > 1)
4260  {
4261  num_ranges++;
4262  if (glyphset)
4263  {
4264  glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4265  glyphset->ranges[num_ranges - 1].cGlyphs = 1;
4266  glyphset->cGlyphsSupported++;
4267  }
4268  }
4269  else if (glyphset)
4270  {
4271  glyphset->ranges[num_ranges - 1].cGlyphs++;
4272  glyphset->cGlyphsSupported++;
4273  }
4274  char_code_prev = char_code;
4275  char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
4276  }
4277  }
4278  else
4279  DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
4280 
4281  size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4282  if (glyphset)
4283  {
4284  glyphset->cbThis = size;
4285  glyphset->cRanges = num_ranges;
4286  glyphset->flAccel = 0;
4287  }
4288  return size;
4289 }
4290 
4291 
4292 BOOL
4293 FASTCALL
4295  HDC hDC,
4296  PTMW_INTERNAL ptmwi)
4297 {
4298  PDC dc;
4299  PDC_ATTR pdcattr;
4300  PTEXTOBJ TextObj;
4301  PFONTGDI FontGDI;
4302  FT_Face Face;
4303  TT_OS2 *pOS2;
4304  TT_HoriHeader *pHori;
4305  FT_WinFNT_HeaderRec Win;
4306  ULONG Error;
4308  LOGFONTW *plf;
4309 
4310  if (!ptmwi)
4311  {
4313  return FALSE;
4314  }
4315 
4316  if (!(dc = DC_LockDc(hDC)))
4317  {
4319  return FALSE;
4320  }
4321  pdcattr = dc->pdcattr;
4322  TextObj = RealizeFontInit(pdcattr->hlfntNew);
4323  if (NULL != TextObj)
4324  {
4325  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4326  FontGDI = ObjToGDI(TextObj->Font, FONT);
4327 
4328  Face = FontGDI->SharedFace->Face;
4329 
4330  IntLockFreeType();
4331  Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
4334 
4335  if (0 != Error)
4336  {
4337  DPRINT1("Error in setting pixel sizes: %u\n", Error);
4338  Status = STATUS_UNSUCCESSFUL;
4339  }
4340  else
4341  {
4342  FT_Face Face = FontGDI->SharedFace->Face;
4343  Status = STATUS_SUCCESS;
4344 
4345  IntLockFreeType();
4346  pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4347  if (NULL == pOS2)
4348  {
4349  DPRINT1("Can't find OS/2 table - not TT font?\n");
4350  Status = STATUS_INTERNAL_ERROR;
4351  }
4352 
4353  pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
4354  if (NULL == pHori)
4355  {
4356  DPRINT1("Can't find HHEA table - not TT font?\n");
4357  Status = STATUS_INTERNAL_ERROR;
4358  }
4359 
4360  Error = FT_Get_WinFNT_Header(Face, &Win);
4361 
4362  if (NT_SUCCESS(Status))
4363  {
4364  FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
4365 
4366  /* FIXME: Fill Diff member */
4367  RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
4368  }
4369 
4371  }
4372  TEXTOBJ_UnlockText(TextObj);
4373  }
4374  else
4375  {
4376  Status = STATUS_INVALID_HANDLE;
4377  }
4378  DC_UnlockDc(dc);
4379 
4380  if (!NT_SUCCESS(Status))
4381  {
4382  SetLastNtError(Status);
4383  return FALSE;
4384  }
4385  return TRUE;
4386 }
4387 
4388 DWORD
4389 FASTCALL
4391  PFONTGDI FontGdi,
4392  DWORD Table,
4393  DWORD Offset,
4394  PVOID Buffer,
4395  DWORD Size)
4396 {
4398  FT_Face Face = FontGdi->SharedFace->Face;
4399 
4400  IntLockFreeType();
4401 
4402  if (FT_IS_SFNT(Face))
4403  {
4404  if (Table)
4405  Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
4406  (Table << 8 & 0xFF0000);
4407 
4408  if (!Buffer) Size = 0;
4409 
4410  if (Buffer && Size)
4411  {
4412  FT_Error Error;
4413  FT_ULong Needed = 0;
4414 
4415  Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
4416 
4417  if ( !Error && Needed < Size) Size = Needed;
4418  }
4419  if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
4420  Result = Size;
4421  }
4422 
4424 
4425  return Result;
4426 }
4427 
4428 #define GOT_PENALTY(name, value) Penalty += (value)
4429 
4430 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
4431 static UINT
4432 GetFontPenalty(const LOGFONTW * LogFont,
4433  const OUTLINETEXTMETRICW * Otm,
4434  const char * style_name)
4435 {
4436  ULONG Penalty = 0;
4437  BYTE Byte;
4438  LONG Long;
4439  BOOL fNeedScaling = FALSE;
4440  const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
4441  const TEXTMETRICW * TM = &Otm->otmTextMetrics;
4442  WCHAR* ActualNameW;
4443 
4444  ASSERT(Otm);
4445  ASSERT(LogFont);
4446 
4447  /* FIXME: IntSizeSynth Penalty 20 */
4448  /* FIXME: SmallPenalty Penalty 1 */
4449  /* FIXME: FaceNameSubst Penalty 500 */
4450 
4451  Byte = LogFont->lfCharSet;
4452  if (Byte == DEFAULT_CHARSET)
4453  {
4454  if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0)
4455  {
4456  if (Byte == ANSI_CHARSET)
4457  {
4458  DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
4459  }
4460  /* We assume SYMBOL_CHARSET for "Marlett" font */
4461  Byte = SYMBOL_CHARSET;
4462  }
4463  }
4464 
4465  if (Byte != TM->tmCharSet)
4466  {
4467  if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
4468  {
4469  /* CharSet Penalty 65000 */
4470  /* Requested charset does not match the candidate's. */
4471  GOT_PENALTY("CharSet", 65000);
4472  }
4473  else
4474  {
4475  if (UserCharSet != TM->tmCharSet)
4476  {
4477  /* UNDOCUMENTED: Not user language */
4478  GOT_PENALTY("UNDOCUMENTED:NotUserLanguage", 100);
4479 
4480  if (ANSI_CHARSET != TM->tmCharSet)
4481  {
4482  /* UNDOCUMENTED: Not ANSI charset */
4483  GOT_PENALTY("UNDOCUMENTED:NotAnsiCharSet", 100);
4484  }
4485  }
4486  }
4487  }
4488 
4489  Byte = LogFont->lfOutPrecision;
4490  switch (Byte)
4491  {
4492  case OUT_DEFAULT_PRECIS:
4493  /* nothing to do */
4494  break;
4495  case OUT_DEVICE_PRECIS:
4496  if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
4498  {
4499  /* OutputPrecision Penalty 19000 */
4500  /* Requested OUT_STROKE_PRECIS, but the device can't do it
4501  or the candidate is not a vector font. */
4502  GOT_PENALTY("OutputPrecision", 19000);
4503  }
4504  break;
4505  default:
4507  {
4508  /* OutputPrecision Penalty 19000 */
4509  /* Or OUT_STROKE_PRECIS not requested, and the candidate
4510  is a vector font that requires GDI support. */
4511  GOT_PENALTY("OutputPrecision", 19000);
4512  }
4513  break;
4514  }
4515 
4516  Byte = (LogFont->lfPitchAndFamily & 0x0F);
4517  if (Byte == DEFAULT_PITCH)
4518  Byte = VARIABLE_PITCH;
4519  if (Byte == FIXED_PITCH)
4520  {
4522  {
4523  /* FixedPitch Penalty 15000 */
4524  /* Requested a fixed pitch font, but the candidate is a
4525  variable pitch font. */
4526  GOT_PENALTY("FixedPitch", 15000);
4527  }
4528  }
4529  if (Byte == VARIABLE_PITCH)
4530  {
4532  {
4533  /* PitchVariable Penalty 350 */
4534  /* Requested a variable pitch font, but the candidate is not a
4535  variable pitch font. */
4536  GOT_PENALTY("PitchVariable", 350);
4537  }
4538  }
4539 
4540  Byte = (LogFont->lfPitchAndFamily & 0x0F);
4541  if (Byte == DEFAULT_PITCH)
4542  {
4544  {
4545  /* DefaultPitchFixed Penalty 1 */
4546  /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
4547  GOT_PENALTY("DefaultPitchFixed", 1);
4548  }
4549  }
4550 
4551  ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
4552 
4553  if (LogFont->lfFaceName[0])
4554  {
4555  BOOL Found = FALSE;
4556 
4557  /* localized family name */
4558  if (!Found)
4559  {
4560  Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4561  }
4562  /* localized full name */
4563  if (!Found)
4564  {
4565  ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
4566  Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4567  }
4568  if (!Found)
4569  {
4570  /* FaceName Penalty 10000 */
4571  /* Requested a face name, but the candidate's face name
4572  does not match. */
4573  GOT_PENALTY("FaceName", 10000);
4574  }
4575  }
4576 
4577  Byte = (LogFont->lfPitchAndFamily & 0xF0);
4578  if (Byte != FF_DONTCARE)
4579  {
4580  if (Byte != (TM->tmPitchAndFamily & 0xF0))
4581  {
4582  /* Family Penalty 9000 */
4583  /* Requested a family, but the candidate's family is different. */
4584  GOT_PENALTY("Family", 9000);
4585  }
4586  }
4587 
4588  if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
4589  {
4590  /* FamilyUnknown Penalty 8000 */
4591  /* Requested a family, but the candidate has no family. */
4592  GOT_PENALTY("FamilyUnknown", 8000);
4593  }
4594 
4595  /* Is the candidate a non-vector font? */
4596  if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4597  {
4598  /* Is lfHeight specified? */
4599  if (LogFont->lfHeight != 0)
4600  {
4601  if (labs(LogFont->lfHeight) < TM->tmHeight)
4602  {
4603  /* HeightBigger Penalty 600 */
4604  /* The candidate is a nonvector font and is bigger than the
4605  requested height. */
4606  GOT_PENALTY("HeightBigger", 600);
4607  /* HeightBiggerDifference Penalty 150 */
4608  /* The candidate is a raster font and is larger than the
4609  requested height. Penalty * height difference */
4610  GOT_PENALTY("HeightBiggerDifference", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)));
4611 
4612  fNeedScaling = TRUE;
4613  }
4614  if (TM->tmHeight < labs(LogFont->lfHeight))
4615  {
4616  /* HeightSmaller Penalty 150 */
4617  /* The candidate is a raster font and is smaller than the
4618  requested height. Penalty * height difference */
4619  GOT_PENALTY("HeightSmaller", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)));
4620 
4621  fNeedScaling = TRUE;
4622  }
4623  }
4624  }
4625 
4626  switch (LogFont->lfPitchAndFamily & 0xF0)
4627  {
4628  case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4629  switch (TM->tmPitchAndFamily & 0xF0)
4630  {
4631  case FF_DECORATIVE: case FF_SCRIPT:
4632  /* FamilyUnlikely Penalty 50 */
4633  /* Requested a roman/modern/swiss family, but the
4634  candidate is decorative/script. */
4635  GOT_PENALTY("FamilyUnlikely", 50);
4636  break;
4637  default:
4638  break;
4639  }
4640  break;
4641  case FF_DECORATIVE: case FF_SCRIPT:
4642  switch (TM->tmPitchAndFamily & 0xF0)
4643  {
4644  case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4645  /* FamilyUnlikely Penalty 50 */
4646  /* Or requested decorative/script, and the candidate is
4647  roman/modern/swiss. */
4648  GOT_PENALTY("FamilyUnlikely", 50);
4649  break;
4650  default:
4651  break;
4652  }
4653  default:
4654  break;
4655  }
4656 
4657  if (LogFont->lfWidth != 0)
4658  {
4659  if (LogFont->lfWidth != TM->tmAveCharWidth)
4660  {
4661  /* Width Penalty 50 */
4662  /* Requested a nonzero width, but the candidate's width
4663  doesn't match. Penalty * width difference */
4664  GOT_PENALTY("Width", 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth));
4665 
4666  if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4667  fNeedScaling = TRUE;
4668  }
4669  }
4670 
4671  if (fNeedScaling)
4672  {
4673  /* SizeSynth Penalty 50 */
4674  /* The candidate is a raster font that needs scaling by GDI. */
4675  GOT_PENALTY("SizeSynth", 50);
4676  }
4677 
4678  if (!!LogFont->lfItalic != !!TM->tmItalic)
4679  {
4680  if (!LogFont->lfItalic && ItalicFromStyle(style_name))
4681  {
4682  /* Italic Penalty 4 */
4683  /* Requested font and candidate font do not agree on italic status,
4684  and the desired result cannot be simulated. */
4685  /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
4686  GOT_PENALTY("Italic", 40);
4687  }
4688  else if (LogFont->lfItalic && !ItalicFromStyle(style_name))
4689  {
4690  /* ItalicSim Penalty 1 */
4691  /* Requested italic font but the candidate is not italic,
4692  although italics can be simulated. */
4693  GOT_PENALTY("ItalicSim", 1);
4694  }
4695  }
4696 
4697  if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
4698  {
4699  if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
4700  {
4701  /* NotTrueType Penalty 4 */
4702  /* Requested OUT_TT_PRECIS, but the candidate is not a
4703  TrueType font. */
4704  GOT_PENALTY("NotTrueType", 4);
4705  }
4706  }
4707 
4708  Long = LogFont->lfWeight;
4709  if (LogFont->lfWeight == FW_DONTCARE)
4710  Long = FW_NORMAL;
4711  if (Long != TM->tmWeight)
4712  {
4713  /* Weight Penalty 3 */
4714  /* The candidate's weight does not match the requested weight.
4715  Penalty * (weight difference/10) */
4716  GOT_PENALTY("Weight", 3 * (labs(Long - TM->tmWeight) / 10));
4717  }
4718 
4719  if (!LogFont->lfUnderline && TM->tmUnderlined)
4720  {
4721  /* Underline Penalty 3 */
4722  /* Requested font has no underline, but the candidate is
4723  underlined. */
4724  GOT_PENALTY("Underline", 3);
4725  }
4726 
4727  if (!LogFont->lfStrikeOut && TM->tmStruckOut)
4728  {
4729  /* StrikeOut Penalty 3 */
4730  /* Requested font has no strike-out, but the candidate is
4731  struck out. */
4732  GOT_PENALTY("StrikeOut", 3);
4733  }
4734 
4735  /* Is the candidate a non-vector font? */
4736  if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4737  {
4738  if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
4739  {
4740  /* VectorHeightSmaller Penalty 2 */
4741  /* Candidate is a vector font that is smaller than the
4742  requested height. Penalty * height difference */
4743  GOT_PENALTY("VectorHeightSmaller", 2 * labs(TM->tmHeight - LogFont->lfHeight));
4744  }
4745  if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
4746  {
4747  /* VectorHeightBigger Penalty 1 */
4748  /* Candidate is a vector font that is bigger than the
4749  requested height. Penalty * height difference */
4750  GOT_PENALTY("VectorHeightBigger", 1 * labs(TM->tmHeight - LogFont->lfHeight));
4751  }
4752  }
4753 
4754  if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
4755  {
4756  /* DeviceFavor Penalty 2 */
4757  /* Extra penalty for all nondevice fonts. */
4758  GOT_PENALTY("DeviceFavor", 2);
4759  }
4760 
4761  if (TM->tmAveCharWidth >= 5 && TM->tmHeight >= 5)
4762  {
4763  if (TM->tmAveCharWidth / TM->tmHeight >= 3)
4764  {
4765  /* Aspect Penalty 30 */
4766  /* The aspect rate is >= 3. It seems like a bad font. */
4767  GOT_PENALTY("Aspect", ((TM->tmAveCharWidth / TM->tmHeight) - 2) * 30);
4768  }
4769  else if (TM->tmHeight / TM->tmAveCharWidth >= 3)
4770  {
4771  /* Aspect Penalty 30 */
4772  /* The aspect rate is >= 3. It seems like a bad font. */
4773  GOT_PENALTY("Aspect", ((TM->tmHeight / TM->tmAveCharWidth) - 2) * 30);
4774  }
4775  }
4776 
4777  if (Penalty < 200)
4778  {
4779  DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
4780  "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
4781  "tmCharSet:%d, tmWeight:%ld\n",
4782  Penalty, LogFont->lfFaceName, ActualNameW,
4783  LogFont->lfCharSet, LogFont->lfWeight,
4784  TM->tmCharSet, TM->tmWeight);
4785  }
4786 
4787  return Penalty; /* success */
4788 }
4789 
4790 #undef GOT_PENALTY
4791 
4792 static __inline VOID
4793 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
4794  const LOGFONTW *LogFont,
4795  const PLIST_ENTRY Head)
4796 {
4797  ULONG Penalty;
4799  PFONT_ENTRY CurrentEntry;
4800  FONTGDI *FontGDI;
4801  OUTLINETEXTMETRICW *Otm = NULL;
4802  UINT OtmSize, OldOtmSize = 0;
4803  FT_Face Face;
4804 
4805  ASSERT(FontObj);
4806  ASSERT(MatchPenalty);
4807  ASSERT(LogFont);
4808  ASSERT(Head);
4809 
4810  /* Start with a pretty big buffer */
4811  OldOtmSize = 0x200;
4812  Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
4813 
4814  /* get the FontObj of lowest penalty */
4815  for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
4816  {
4817  CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
4818 
4819  FontGDI = CurrentEntry->Font;
4820  ASSERT(FontGDI);
4821  Face = FontGDI->SharedFace->Face;
4822 
4823  /* get text metrics */
4824  OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4825  if (OtmSize > OldOtmSize)
4826  {
4827  if (Otm)
4829  Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
4830  }
4831 
4832  /* update FontObj if lowest penalty */
4833  if (Otm)
4834  {
4835  IntLockFreeType();
4836  IntRequestFontSize(NULL, FontGDI, LogFont->lfWidth, LogFont->lfHeight);
4838 
4839  OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
4840  if (!OtmSize)
4841  continue;
4842 
4843  OldOtmSize = OtmSize;
4844 
4845  Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
4846  if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
4847  {
4848  *FontObj = GDIToObj(FontGDI, FONT);
4849  *MatchPenalty = Penalty;
4850  }
4851  }
4852  }
4853 
4854  if (Otm)
4856 }
4857 
4858 static
4859 VOID
4860 FASTCALL
4862 {
4863  PS_FontInfoRec psfInfo;
4864  FT_ULong tmp_size = 0;
4865  FT_Face Face = Font->SharedFace->Face;
4866 
4867  if (FT_HAS_MULTIPLE_MASTERS(Face))
4869  if (FT_HAS_VERTICAL(Face))
4870  Font->FontObj.flFontType |= FO_VERT_FACE;
4871  if (!FT_IS_SCALABLE(Face))
4873  if (FT_IS_SFNT(Face))
4874  {
4876  if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
4877  Font->FontObj.flFontType |= FO_POSTSCRIPT;
4878  }
4879  if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
4880  {
4881  Font->FontObj.flFontType |= FO_POSTSCRIPT;
4882  }
4883  /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
4884  if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
4885  {
4887  }
4888 }
4889 
4890 static BOOL
4891 MatchFontName(PSHARED_FACE SharedFace, LPCWSTR lfFaceName, FT_UShort NameID, FT_UShort LangID)
4892 {
4893  NTSTATUS Status;
4894  UNICODE_STRING Name1, Name2;
4895 
4896  if (lfFaceName[0] == UNICODE_NULL)
4897  return FALSE;
4898 
4899  RtlInitUnicodeString(&Name1, lfFaceName);
4900 
4901  RtlInitUnicodeString(&Name2, NULL);
4902  Status = IntGetFontLocalizedName(&Name2, SharedFace, NameID, LangID);
4903 
4904  if (NT_SUCCESS(Status))
4905  {
4906  if (RtlCompareUnicodeString(&Name1, &Name2, TRUE) == 0)
4907  {
4908  RtlFreeUnicodeString(&Name2);
4909  return TRUE;
4910  }
4911 
4912  RtlFreeUnicodeString(&Name2);
4913  }
4914 
4915  return FALSE;
4916 }
4917 
4918 static BOOL
4919 MatchFontNames(PSHARED_FACE SharedFace, LPCWSTR lfFaceName)
4920 {
4921  if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, LANG_ENGLISH) ||
4922  MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, LANG_ENGLISH))
4923  {
4924  return TRUE;
4925  }
4927  {
4928  if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, gusLanguageID) ||
4929  MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, gusLanguageID))
4930  {
4931  return TRUE;
4932  }
4933  }
4934  return FALSE;
4935 }
4936 
4937 NTSTATUS
4938 FASTCALL
4939 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
4940 {
4942  PTEXTOBJ TextObj;
4943  PPROCESSINFO Win32Process;
4944  ULONG MatchPenalty;
4945  LOGFONTW *pLogFont;
4946  LOGFONTW SubstitutedLogFont;
4947  FT_Face Face;
4948 
4949  if (!pTextObj)
4950  {
4951  TextObj = TEXTOBJ_LockText(FontHandle);
4952  if (NULL == TextObj)
4953  {
4954  return STATUS_INVALID_HANDLE;
4955  }
4956 
4957  if (TextObj->fl & TEXTOBJECT_INIT)
4958  {
4959  TEXTOBJ_UnlockText(TextObj);
4960  return STATUS_SUCCESS;
4961  }
4962  }
4963  else
4964  {
4965  TextObj = pTextObj;
4966  }
4967 
4968  pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4969 
4970  /* substitute */
4971  SubstitutedLogFont = *pLogFont;
4972  DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
4973  SubstituteFontRecurse(&SubstitutedLogFont);
4974  DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
4975 
4976  MatchPenalty = 0xFFFFFFFF;
4977  TextObj->Font = NULL;
4978 
4979  Win32Process = PsGetCurrentProcessWin32Process();
4980 
4981  /* Search private fonts */
4982  IntLockProcessPrivateFonts(Win32Process);
4983  FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4984  &Win32Process->PrivateFontListHead);
4985  IntUnLockProcessPrivateFonts(Win32Process);
4986 
4987  /* Search system fonts */
4989  FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4990  &g_FontListHead);
4992 
4993  if (NULL == TextObj->Font)
4994  {
4995  DPRINT1("Request font %S not found, no fonts loaded at all\n",
4996  pLogFont->lfFaceName);
4997  Status = STATUS_NOT_FOUND;
4998  }
4999  else
5000  {
5002  PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
5003  PSHARED_FACE SharedFace = FontGdi->SharedFace;
5004 
5005  IntLockFreeType();
5006  IntRequestFontSize(NULL, FontGdi, pLogFont->lfWidth, pLogFont->lfHeight);
5008 
5009  TextObj->TextFace[0] = UNICODE_NULL;
5010  if (MatchFontNames(SharedFace, SubstitutedLogFont.lfFaceName))
5011  {
5012  RtlStringCchCopyW(TextObj->TextFace, _countof(TextObj->TextFace), pLogFont->lfFaceName);
5013  }
5014  else
5015  {
5016  RtlInitUnicodeString(&Name, NULL);
5017  Status = IntGetFontLocalizedName(&Name, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
5018  if (NT_SUCCESS(Status))
5019  {
5020  /* truncated copy */
5021  IntUnicodeStringToBuffer(TextObj->