ReactOS  0.4.11-dev-195-gef016bf
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 BOOL
746 {
747  UINT RecurseCount = 5;
748  UNICODE_STRING OutputNameW = { 0 };
749  BYTE CharSetMap[FONTSUBST_FROM_AND_TO];
750  BOOL Found;
751  UNICODE_STRING InputNameW;
752 
753  if (pLogFont->lfFaceName[0] == UNICODE_NULL)
754  return FALSE;
755 
756  RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
757 
758  while (RecurseCount-- > 0)
759  {
760  Found = SubstituteFontByList(&g_FontSubstListHead,
761  &OutputNameW, &InputNameW,
762  pLogFont->lfCharSet, CharSetMap);
763  if (!Found)
764  break;
765 
766  RtlStringCchCopyW(pLogFont->lfFaceName, LF_FACESIZE, OutputNameW.Buffer);
767 
768  if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
769  CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
770  {
771  pLogFont->lfCharSet = CharSetMap[FONTSUBST_TO];
772  }
773  }
774 
775  return TRUE; /* success */
776 }
777 
778 /*
779  * IntLoadSystemFonts
780  *
781  * Search the system font directory and adds each font found.
782  */
785 {
787  UNICODE_STRING Directory, FileName, TempString;
789  HANDLE hDirectory;
790  BYTE *DirInfoBuffer;
792  BOOLEAN bRestartScan = TRUE;
794  INT i;
795  static UNICODE_STRING SearchPatterns[] =
796  {
797  RTL_CONSTANT_STRING(L"*.ttf"),
798  RTL_CONSTANT_STRING(L"*.ttc"),
799  RTL_CONSTANT_STRING(L"*.otf"),
800  RTL_CONSTANT_STRING(L"*.otc"),
801  RTL_CONSTANT_STRING(L"*.fon"),
802  RTL_CONSTANT_STRING(L"*.fnt")
803  };
804 
805  RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
806 
808  &ObjectAttributes,
809  &Directory,
811  NULL,
812  NULL);
813 
814  Status = ZwOpenFile(
815  &hDirectory,
817  &ObjectAttributes,
818  &Iosb,
821 
822  if (NT_SUCCESS(Status))
823  {
824  for (i = 0; i < _countof(SearchPatterns); ++i)
825  {
826  DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
827  if (DirInfoBuffer == NULL)
828  {
829  ZwClose(hDirectory);
830  return;
831  }
832 
834  if (FileName.Buffer == NULL)
835  {
836  ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
837  ZwClose(hDirectory);
838  return;
839  }
840  FileName.Length = 0;
841  FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
842 
843  while (1)
844  {
845  Status = ZwQueryDirectoryFile(
846  hDirectory,
847  NULL,
848  NULL,
849  NULL,
850  &Iosb,
851  DirInfoBuffer,
852  0x4000,
854  FALSE,
855  &SearchPatterns[i],
856  bRestartScan);
857 
858  if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
859  {
860  break;
861  }
862 
863  DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
864  while (1)
865  {
866  TempString.Buffer = DirInfo->FileName;
867  TempString.Length =
868  TempString.MaximumLength = DirInfo->FileNameLength;
869  RtlCopyUnicodeString(&FileName, &Directory);
870  RtlAppendUnicodeStringToString(&FileName, &TempString);
871  IntGdiAddFontResource(&FileName, 0);
872  if (DirInfo->NextEntryOffset == 0)
873  break;
874  DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
875  }
876 
877  bRestartScan = FALSE;
878  }
879 
880  ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
881  ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
882  }
883  ZwClose(hDirectory);
884  }
885 }
886 
887 static BYTE
888 ItalicFromStyle(const char *style_name)
889 {
890  if (style_name == NULL || style_name[0] == 0)
891  return FALSE;
892  if (strstr(style_name, "Italic") != NULL)
893  return TRUE;
894  if (strstr(style_name, "Oblique") != NULL)
895  return TRUE;
896  return FALSE;
897 }
898 
899 static LONG
900 WeightFromStyle(const char *style_name)
901 {
902  if (style_name == NULL || style_name[0] == 0)
903  return FW_NORMAL;
904  if (strstr(style_name, "Regular") != NULL)
905  return FW_REGULAR;
906  if (strstr(style_name, "Normal") != NULL)
907  return FW_NORMAL;
908  if (strstr(style_name, "SemiBold") != NULL)
909  return FW_SEMIBOLD;
910  if (strstr(style_name, "UltraBold") != NULL)
911  return FW_ULTRABOLD;
912  if (strstr(style_name, "DemiBold") != NULL)
913  return FW_DEMIBOLD;
914  if (strstr(style_name, "ExtraBold") != NULL)
915  return FW_EXTRABOLD;
916  if (strstr(style_name, "Bold") != NULL)
917  return FW_BOLD;
918  if (strstr(style_name, "UltraLight") != NULL)
919  return FW_ULTRALIGHT;
920  if (strstr(style_name, "ExtraLight") != NULL)
921  return FW_EXTRALIGHT;
922  if (strstr(style_name, "Light") != NULL)
923  return FW_LIGHT;
924  if (strstr(style_name, "Hairline") != NULL)
925  return 50;
926  if (strstr(style_name, "Book") != NULL)
927  return 350;
928  if (strstr(style_name, "ExtraBlack") != NULL)
929  return 950;
930  if (strstr(style_name, "UltraBlack") != NULL)
931  return 1000;
932  if (strstr(style_name, "Black") != NULL)
933  return FW_BLACK;
934  if (strstr(style_name, "Medium") != NULL)
935  return FW_MEDIUM;
936  if (strstr(style_name, "Thin") != NULL)
937  return FW_THIN;
938  if (strstr(style_name, "Heavy") != NULL)
939  return FW_HEAVY;
940  return FW_NORMAL;
941 }
942 
943 static FT_Error
944 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight);
945 
946 static INT FASTCALL
948  PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
949 {
950  FT_Error Error;
952  FONT_ENTRY_MEM* PrivateEntry = NULL;
953  FONTGDI * FontGDI;
955  FT_Face Face;
956  ANSI_STRING AnsiFaceName;
957  FT_WinFNT_HeaderRec WinFNT;
958  INT FaceCount = 0, CharSetCount = 0;
959  PUNICODE_STRING pFileName = pLoadFont->pFileName;
960  DWORD Characteristics = pLoadFont->Characteristics;
961  PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
962  TT_OS2 * pOS2;
963  INT BitIndex;
964  FT_UShort os2_version;
965  FT_ULong os2_ulCodePageRange1;
966  FT_UShort os2_usWeightClass;
967 
968  if (SharedFace == NULL && CharSetIndex == -1)
969  {
970  /* load a face from memory */
971  IntLockFreeType();
972  Error = FT_New_Memory_Face(
973  g_FreeTypeLibrary,
974  pLoadFont->Memory->Buffer,
975  pLoadFont->Memory->BufferSize,
976  ((FontIndex != -1) ? FontIndex : 0),
977  &Face);
978 
979  if (!Error)
980  SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
981 
983 
984  if (!Error && FT_IS_SFNT(Face))
985  pLoadFont->IsTrueType = TRUE;
986 
987  if (Error || SharedFace == NULL)
988  {
989  if (SharedFace)
990  SharedFace_Release(SharedFace);
991 
992  if (Error == FT_Err_Unknown_File_Format)
993  DPRINT1("Unknown font file format\n");
994  else
995  DPRINT1("Error reading font (error code: %d)\n", Error);
996  return 0; /* failure */
997  }
998  }
999  else
1000  {
1001  Face = SharedFace->Face;
1002  IntLockFreeType();
1003  SharedFace_AddRef(SharedFace);
1005  }
1006 
1007  /* allocate a FONT_ENTRY */
1009  if (!Entry)
1010  {
1011  SharedFace_Release(SharedFace);
1013  return 0; /* failure */
1014  }
1015 
1016  /* allocate a FONTGDI */
1017  FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
1018  if (!FontGDI)
1019  {
1020  SharedFace_Release(SharedFace);
1021  ExFreePoolWithTag(Entry, TAG_FONT);
1023  return 0; /* failure */
1024  }
1025 
1026  /* set file name */
1027  if (pFileName)
1028  {
1030  pFileName->Length + sizeof(UNICODE_NULL),
1031  GDITAG_PFF);
1032  if (FontGDI->Filename == NULL)
1033  {
1034  EngFreeMem(FontGDI);
1035  SharedFace_Release(SharedFace);
1036  ExFreePoolWithTag(Entry, TAG_FONT);
1038  return 0; /* failure */
1039  }
1040  RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
1041  FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1042  }
1043  else
1044  {
1045  FontGDI->Filename = NULL;
1046 
1047  PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT);
1048  if (!PrivateEntry)
1049  {
1050  if (FontGDI->Filename)
1052  EngFreeMem(FontGDI);
1053  SharedFace_Release(SharedFace);
1054  ExFreePoolWithTag(Entry, TAG_FONT);
1055  return 0;
1056  }
1057 
1058  PrivateEntry->Entry = Entry;
1059  if (pLoadFont->PrivateEntry)
1060  {
1061  InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry);
1062  }
1063  else
1064  {
1065  InitializeListHead(&PrivateEntry->ListEntry);
1066  pLoadFont->PrivateEntry = PrivateEntry;
1067  }
1068  }
1069 
1070  /* set face */
1071  FontGDI->SharedFace = SharedFace;
1072  FontGDI->CharSet = ANSI_CHARSET;
1073  FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name);
1074  FontGDI->RequestItalic = FALSE;
1075  FontGDI->OriginalWeight = WeightFromStyle(Face->style_name);
1076  FontGDI->RequestWeight = FW_NORMAL;
1077 
1078  RtlInitAnsiString(&AnsiFaceName, Face->family_name);
1079  Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
1080  if (!NT_SUCCESS(Status))
1081  {
1082  if (PrivateEntry)
1083  {
1084  if (pLoadFont->PrivateEntry == PrivateEntry)
1085  {
1086  pLoadFont->PrivateEntry = NULL;
1087  }
1088  else
1089  {
1090  RemoveEntryList(&PrivateEntry->ListEntry);
1091  }
1092  ExFreePoolWithTag(PrivateEntry, TAG_FONT);
1093  }
1094  if (FontGDI->Filename)
1096  EngFreeMem(FontGDI);
1097  SharedFace_Release(SharedFace);
1098  ExFreePoolWithTag(Entry, TAG_FONT);
1099  return 0;
1100  }
1101 
1102  os2_version = 0;
1103  IntLockFreeType();
1104  pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
1105  if (pOS2)
1106  {
1107  os2_version = pOS2->version;
1108  os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
1109  os2_usWeightClass = pOS2->usWeightClass;
1110  }
1112 
1113  if (pOS2 && os2_version >= 1)
1114  {
1115  /* get charset and weight from OS/2 header */
1116 
1117  /* Make sure we do not use this pointer anymore */
1118  pOS2 = NULL;
1119 
1120  for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
1121  {
1122  if (os2_ulCodePageRange1 & (1 << BitIndex))
1123  {
1124  if (g_FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
1125  continue;
1126 
1127  if ((CharSetIndex == -1 && CharSetCount == 0) ||
1128  CharSetIndex == CharSetCount)
1129  {
1130  FontGDI->CharSet = g_FontTci[BitIndex].ciCharset;
1131  }
1132 
1133  ++CharSetCount;
1134  }
1135  }
1136 
1137  /* set actual weight */
1138  FontGDI->OriginalWeight = os2_usWeightClass;
1139  }
1140  else
1141  {
1142  /* get charset from WinFNT header */
1143  IntLockFreeType();
1144  Error = FT_Get_WinFNT_Header(Face, &WinFNT);
1145  if (!Error)
1146  {
1147  FontGDI->CharSet = WinFNT.charset;
1148  }
1150  }
1151 
1152  /* FIXME: CharSet is invalid on Marlett */
1153  if (RtlEqualUnicodeString(&Entry->FaceName, &g_MarlettW, TRUE))
1154  {
1155  FontGDI->CharSet = SYMBOL_CHARSET;
1156  }
1157 
1158  ++FaceCount;
1159  DPRINT("Font loaded: %s (%s)\n",
1160  Face->family_name ? Face->family_name : "<NULL>",
1161  Face->style_name ? Face->style_name : "<NULL>");
1162  DPRINT("Num glyphs: %d\n", Face->num_glyphs);
1163  DPRINT("CharSet: %d\n", FontGDI->CharSet);
1164 
1165  IntLockFreeType();
1166  IntRequestFontSize(NULL, FontGDI, 0, 0);
1168 
1169  /* Add this font resource to the font table */
1170  Entry->Font = FontGDI;
1171  Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
1172 
1173  if (Characteristics & FR_PRIVATE)
1174  {
1175  /* private font */
1177  IntLockProcessPrivateFonts(Win32Process);
1178  InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
1179  IntUnLockProcessPrivateFonts(Win32Process);
1180  }
1181  else
1182  {
1183  /* global font */
1185  InsertTailList(&g_FontListHead, &Entry->ListEntry);
1187  }
1188 
1189  if (FontIndex == -1)
1190  {
1191  if (FT_IS_SFNT(Face))
1192  {
1193  TT_Face TrueType = (TT_Face)Face;
1194  if (TrueType->ttc_header.count > 1)
1195  {
1196  FT_Long i;
1197  for (i = 1; i < TrueType->ttc_header.count; ++i)
1198  {
1199  FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
1200  }
1201  }
1202  }
1203  FontIndex = 0;
1204  }
1205 
1206  if (CharSetIndex == -1)
1207  {
1208  INT i;
1209 
1210  if (pLoadFont->RegValueName.Length == 0)
1211  {
1212  RtlCreateUnicodeString(pValueName, Entry->FaceName.Buffer);
1213  }
1214  else
1215  {
1216  UNICODE_STRING NewString;
1217  USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + Entry->FaceName.Length;
1218  NewString.Length = 0;
1219  NewString.MaximumLength = Length + sizeof(WCHAR);
1221  NewString.MaximumLength,
1222  TAG_USTR);
1223  NewString.Buffer[0] = UNICODE_NULL;
1224 
1225  RtlAppendUnicodeStringToString(&NewString, pValueName);
1226  RtlAppendUnicodeToString(&NewString, L" & ");
1227  RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
1228 
1229  RtlFreeUnicodeString(pValueName);
1230  *pValueName = NewString;
1231  }
1232 
1233  for (i = 1; i < CharSetCount; ++i)
1234  {
1235  /* Do not count charsets towards 'faces' loaded */
1236  IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
1237  }
1238  }
1239 
1240  return FaceCount; /* number of loaded faces */
1241 }
1242 
1243 /*
1244  * IntGdiAddFontResource
1245  *
1246  * Adds the font resource from the specified file to the system.
1247  */
1248 
1249 INT FASTCALL
1251 {
1252  NTSTATUS Status;
1254  PVOID Buffer = NULL;
1257  SIZE_T ViewSize = 0;
1258  LARGE_INTEGER SectionSize;
1261  INT FontCount;
1262  HANDLE KeyHandle;
1263  static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
1264 
1265  /* Open the font file */
1266  InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
1267  Status = ZwOpenFile(
1268  &FileHandle,
1270  &ObjectAttributes,
1271  &Iosb,
1274  if (!NT_SUCCESS(Status))
1275  {
1276  DPRINT("Could not load font file: %wZ\n", FileName);
1277  return 0;
1278  }
1279 
1280  SectionSize.QuadPart = 0LL;
1281  Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
1282  NULL, &SectionSize, PAGE_READONLY,
1283  SEC_COMMIT, FileHandle, NULL);
1284  if (!NT_SUCCESS(Status))
1285  {
1286  DPRINT("Could not map file: %wZ\n", FileName);
1287  ZwClose(FileHandle);
1288  return 0;
1289  }
1290  ZwClose(FileHandle);
1291 
1292  Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
1293  if (!NT_SUCCESS(Status))
1294  {
1295  DPRINT("Could not map file: %wZ\n", FileName);
1296  ObDereferenceObject(SectionObject);
1297  return 0;
1298  }
1299 
1300  LoadFont.pFileName = FileName;
1301  LoadFont.Memory = SharedMem_Create(Buffer, ViewSize, TRUE);
1302  LoadFont.Characteristics = Characteristics;
1304  LoadFont.IsTrueType = FALSE;
1305  LoadFont.PrivateEntry = NULL;
1306  FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1307 
1308  ObDereferenceObject(SectionObject);
1309 
1310  /* Release our copy */
1311  IntLockFreeType();
1312  SharedMem_Release(LoadFont.Memory);
1314 
1315  if (FontCount > 0)
1316  {
1317  if (LoadFont.IsTrueType)
1318  {
1319  /* append " (TrueType)" */
1320  UNICODE_STRING NewString;
1321  USHORT Length;
1322 
1323  Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length;
1324  NewString.Length = 0;
1325  NewString.MaximumLength = Length + sizeof(WCHAR);
1327  NewString.MaximumLength,
1328  TAG_USTR);
1329  NewString.Buffer[0] = UNICODE_NULL;
1330 
1331  RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
1332  RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
1334  LoadFont.RegValueName = NewString;
1335  }
1336 
1337  /* registry */
1338  InitializeObjectAttributes(&ObjectAttributes, &g_FontRegPath,
1340  NULL, NULL);
1341  Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
1342  if (NT_SUCCESS(Status))
1343  {
1344  SIZE_T DataSize;
1345  LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
1346  if (pFileName)
1347  {
1348  pFileName++;
1349  DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
1350  ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
1351  pFileName, DataSize);
1352  }
1353  ZwClose(KeyHandle);
1354  }
1355  }
1357 
1358  return FontCount;
1359 }
1360 
1363 {
1365  FONT_ENTRY_COLL_MEM* EntryCollection;
1366  INT FaceCount;
1367  HANDLE Ret = 0;
1368 
1369  PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
1370 
1371  if (!BufferCopy)
1372  {
1373  *pNumAdded = 0;
1374  return NULL;
1375  }
1376  memcpy(BufferCopy, Buffer, dwSize);
1377 
1378  LoadFont.pFileName = NULL;
1379  LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
1380  LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
1382  LoadFont.IsTrueType = FALSE;
1383  LoadFont.PrivateEntry = NULL;
1384  FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1385 
1387 
1388  /* Release our copy */
1389  IntLockFreeType();
1390  SharedMem_Release(LoadFont.Memory);
1392 
1393  if (FaceCount > 0)
1394  {
1395  EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
1396  if (EntryCollection)
1397  {
1399  EntryCollection->Entry = LoadFont.PrivateEntry;
1400  IntLockProcessPrivateFonts(Win32Process);
1401  EntryCollection->Handle = ULongToHandle(++Win32Process->PrivateMemFontHandleCount);
1402  InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
1403  IntUnLockProcessPrivateFonts(Win32Process);
1404  Ret = EntryCollection->Handle;
1405  }
1406  }
1407  *pNumAdded = FaceCount;
1408 
1409  return Ret;
1410 }
1411 
1412 // FIXME: Add RemoveFontResource
1413 
1414 static VOID FASTCALL
1416 {
1417  PFONTGDI FontGDI = FontEntry->Font;
1418  PSHARED_FACE SharedFace = FontGDI->SharedFace;
1419 
1420  if (FontGDI->Filename)
1422 
1423  EngFreeMem(FontGDI);
1424  SharedFace_Release(SharedFace);
1425  ExFreePoolWithTag(FontEntry, TAG_FONT);
1426 }
1427 
1428 VOID FASTCALL
1430 {
1432  PFONT_ENTRY_MEM FontEntry;
1433 
1434  while (!IsListEmpty(&Head->ListEntry))
1435  {
1436  Entry = RemoveHeadList(&Head->ListEntry);
1437  FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
1438 
1439  CleanupFontEntry(FontEntry->Entry);
1440  ExFreePoolWithTag(FontEntry, TAG_FONT);
1441  }
1442 
1443  CleanupFontEntry(Head->Entry);
1444  ExFreePoolWithTag(Head, TAG_FONT);
1445 }
1446 
1447 static VOID FASTCALL
1449 {
1450  PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
1451  PLIST_ENTRY ListEntry;
1452  RemoveEntryList(&Collection->ListEntry);
1453 
1454  do {
1455  /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
1456  RemoveEntryList(&FontMemEntry->Entry->ListEntry);
1457 
1458  ListEntry = FontMemEntry->ListEntry.Flink;
1459  FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
1460 
1461  } while (FontMemEntry != Collection->Entry);
1462 }
1463 
1464 BOOL FASTCALL
1466 {
1468  PFONT_ENTRY_COLL_MEM CurrentEntry;
1469  PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
1471 
1472  IntLockProcessPrivateFonts(Win32Process);
1473  for (Entry = Win32Process->PrivateMemFontListHead.Flink;
1474  Entry != &Win32Process->PrivateMemFontListHead;
1475  Entry = Entry->Flink)
1476  {
1477  CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1478 
1479  if (CurrentEntry->Handle == hMMFont)
1480  {
1481  EntryCollection = CurrentEntry;
1482  UnlinkFontMemCollection(CurrentEntry);
1483  break;
1484  }
1485  }
1486  IntUnLockProcessPrivateFonts(Win32Process);
1487 
1488  if (EntryCollection)
1489  {
1490  IntGdiCleanupMemEntry(EntryCollection->Entry);
1491  ExFreePoolWithTag(EntryCollection, TAG_FONT);
1492  return TRUE;
1493  }
1494  return FALSE;
1495 }
1496 
1497 
1498 VOID FASTCALL
1500 {
1503  PFONT_ENTRY_COLL_MEM EntryCollection;
1504 
1505  DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
1506  do {
1507  Entry = NULL;
1508  EntryCollection = NULL;
1509 
1510  IntLockProcessPrivateFonts(Win32Process);
1511  if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
1512  {
1513  Entry = Win32Process->PrivateMemFontListHead.Flink;
1514  EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1515  UnlinkFontMemCollection(EntryCollection);
1516  }
1517  IntUnLockProcessPrivateFonts(Win32Process);
1518 
1519  if (EntryCollection)
1520  {
1521  IntGdiCleanupMemEntry(EntryCollection->Entry);
1522  ExFreePoolWithTag(EntryCollection, TAG_FONT);
1523  }
1524  else
1525  {
1526  /* No Mem fonts anymore, see if we have any other private fonts left */
1527  Entry = NULL;
1528  IntLockProcessPrivateFonts(Win32Process);
1529  if (!IsListEmpty(&Win32Process->PrivateFontListHead))
1530  {
1531  Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
1532  }
1533  IntUnLockProcessPrivateFonts(Win32Process);
1534 
1535  if (Entry)
1536  {
1537  CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
1538  }
1539  }
1540 
1541  } while (Entry);
1542 }
1543 
1544 BOOL FASTCALL
1546 {
1547  BOOL Ret = g_RenderingEnabled;
1548  HDC hDC;
1549 
1550  hDC = IntGetScreenDC();
1551  if (hDC)
1552  Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && g_RenderingEnabled;
1553 
1554  return Ret;
1555 }
1556 
1557 VOID FASTCALL
1559 {
1561 }
1562 
1565 {
1566  switch (logfont->lfQuality)
1567  {
1568  case ANTIALIASED_QUALITY:
1569  break;
1571  return FT_RENDER_MODE_MONO;
1572  case DRAFT_QUALITY:
1573  return FT_RENDER_MODE_LIGHT;
1574  /* case CLEARTYPE_QUALITY:
1575  return FT_RENDER_MODE_LCD; */
1576  }
1577  return FT_RENDER_MODE_NORMAL;
1578 }
1579 
1580 
1583 {
1584  PLFONT plfont;
1585  LOGFONTW *plf;
1586 
1587  plfont = LFONT_AllocFontWithHandle();
1588  if (!plfont)
1589  {
1590  return STATUS_NO_MEMORY;
1591  }
1592 
1593  ExInitializePushLock(&plfont->lock);
1594  *NewFont = plfont->BaseObject.hHmgr;
1595  plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
1596  RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
1597  if (lf->lfEscapement != lf->lfOrientation)
1598  {
1599  /* This should really depend on whether GM_ADVANCED is set */
1600  plf->lfOrientation = plf->lfEscapement;
1601  }
1602  LFONT_UnlockFont(plfont);
1603 
1604  return STATUS_SUCCESS;
1605 }
1606 
1607 /*************************************************************************
1608  * TranslateCharsetInfo
1609  *
1610  * Fills a CHARSETINFO structure for a character set, code page, or
1611  * font. This allows making the correspondance between different labelings
1612  * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
1613  * of the same encoding.
1614  *
1615  * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
1616  * only one codepage should be set in *Src.
1617  *
1618  * RETURNS
1619  * TRUE on success, FALSE on failure.
1620  *
1621  */
1622 static BOOLEAN APIENTRY
1624  if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
1625  if flags == TCI_SRCCHARSET: a character set value
1626  if flags == TCI_SRCCODEPAGE: a code page value */
1627  LPCHARSETINFO Cs, /* [out] structure to receive charset information */
1628  DWORD Flags /* [in] determines interpretation of lpSrc */)
1629 {
1630  int Index = 0;
1631 
1632  switch (Flags)
1633  {
1634  case TCI_SRCFONTSIG:
1635  while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
1636  {
1637  Index++;
1638  }
1639  break;
1640  case TCI_SRCCODEPAGE:
1641  while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciACP)
1642  {
1643  Index++;
1644  }
1645  break;
1646  case TCI_SRCCHARSET:
1647  while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciCharset)
1648  {
1649  Index++;
1650  }
1651  break;
1652  case TCI_SRCLOCALE:
1653  UNIMPLEMENTED;
1654  return FALSE;
1655  default:
1656  return FALSE;
1657  }
1658 
1659  if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == g_FontTci[Index].ciCharset)
1660  {
1661  return FALSE;
1662  }
1663 
1664  RtlCopyMemory(Cs, &g_FontTci[Index], sizeof(CHARSETINFO));
1665 
1666  return TRUE;
1667 }
1668 
1669 
1671 {
1672  int i;
1673 
1674  for(i = 0; i < ft_face->num_charmaps; i++)
1675  {
1676  if (ft_face->charmaps[i]->platform_id == TT_PLATFORM_MICROSOFT &&
1677  ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
1678  {
1679  return TRUE;
1680  }
1681  }
1682  return FALSE;
1683 }
1684 
1685 static void FASTCALL
1687  TT_OS2 *pOS2, TT_HoriHeader *pHori,
1688  FT_WinFNT_HeaderRec *pFNT, BOOL RealFont)
1689 {
1690  FT_Fixed XScale, YScale;
1691  int Ascent, Descent;
1692  FT_Face Face = FontGDI->SharedFace->Face;
1693 
1694  XScale = Face->size->metrics.x_scale;
1695  YScale = Face->size->metrics.y_scale;
1696 
1697  if (pFNT)
1698  {
1699  TM->tmHeight = pFNT->pixel_height;
1700  TM->tmAscent = pFNT->ascent;
1701  TM->tmDescent = TM->tmHeight - TM->tmAscent;
1702  TM->tmInternalLeading = pFNT->internal_leading;
1703  TM->tmExternalLeading = pFNT->external_leading;
1704  TM->tmAveCharWidth = pFNT->avg_width;
1705  TM->tmMaxCharWidth = pFNT->max_width;
1706  TM->tmOverhang = 0;
1709  TM->tmFirstChar = pFNT->first_char;
1710  TM->tmLastChar = pFNT->last_char;
1711  TM->tmDefaultChar = pFNT->default_char + pFNT->first_char;
1712  TM->tmBreakChar = pFNT->break_char + pFNT->first_char;
1713  TM->tmPitchAndFamily = pFNT->pitch_and_family;
1714  if (RealFont)
1715  {
1716  TM->tmWeight = FontGDI->OriginalWeight;
1717  TM->tmItalic = FontGDI->OriginalItalic;
1718  TM->tmUnderlined = pFNT->underline;
1719  TM->tmStruckOut = pFNT->strike_out;
1720  TM->tmCharSet = pFNT->charset;
1721  }
1722  else
1723  {
1724  TM->tmWeight = FontGDI->RequestWeight;
1725  TM->tmItalic = FontGDI->RequestItalic;
1726  TM->tmUnderlined = FontGDI->RequestUnderline;
1727  TM->tmStruckOut = FontGDI->RequestStrikeOut;
1728  TM->tmCharSet = FontGDI->CharSet;
1729  }
1730  return;
1731  }
1732 
1733  if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
1734  {
1735  Ascent = pHori->Ascender;
1736  Descent = -pHori->Descender;
1737  }
1738  else
1739  {
1740  Ascent = pOS2->usWinAscent;
1741  Descent = pOS2->usWinDescent;
1742  }
1743 
1744  if (FontGDI->Magic != FONTGDI_MAGIC)
1745  {
1746  IntRequestFontSize(NULL, FontGDI, 0, 0);
1747  }
1748  TM->tmAscent = FontGDI->tmAscent;
1749  TM->tmDescent = FontGDI->tmDescent;
1750  TM->tmHeight = TM->tmAscent + TM->tmDescent;
1751  TM->tmInternalLeading = FontGDI->tmInternalLeading;
1752 
1753  /* MSDN says:
1754  * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1755  */
1756  TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
1757  - ((Ascent + Descent)
1758  - (pHori->Ascender - pHori->Descender)),
1759  YScale) + 32) >> 6);
1760 
1761  TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
1762  if (TM->tmAveCharWidth == 0)
1763  {
1764  TM->tmAveCharWidth = 1;
1765  }
1766 
1767  /* Correct forumla to get the maxcharwidth from unicode and ansi font */
1768  TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
1769 
1770  if (RealFont)
1771  {
1772  TM->tmWeight = FontGDI->OriginalWeight;
1773  }
1774  else
1775  {
1776  if (FontGDI->OriginalWeight != FW_DONTCARE &&
1777  FontGDI->OriginalWeight != FW_NORMAL)
1778  {
1779  TM->tmWeight = FontGDI->OriginalWeight;
1780  }
1781  else
1782  {
1783  TM->tmWeight = FontGDI->RequestWeight;
1784  }
1785  }
1786 
1787  TM->tmOverhang = 0;
1788  TM->tmDigitizedAspectX = 96;
1789  TM->tmDigitizedAspectY = 96;
1790  if (face_has_symbol_charmap(Face) ||
1791  (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
1792  {
1793  USHORT cpOEM, cpAnsi;
1794 
1795  EngGetCurrentCodePage(&cpOEM, &cpAnsi);
1796  TM->tmFirstChar = 0;
1797  switch(cpAnsi)
1798  {
1799  case 1257: /* Baltic */
1800  TM->tmLastChar = 0xf8fd;
1801  break;
1802  default:
1803  TM->tmLastChar = 0xf0ff;
1804  }
1805  TM->tmBreakChar = 0x20;
1806  TM->tmDefaultChar = 0x1f;
1807  }
1808  else
1809  {
1810  TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
1811  TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
1812 
1813  if(pOS2->usFirstCharIndex <= 1)
1814  TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
1815  else if (pOS2->usFirstCharIndex > 0xff)
1816  TM->tmBreakChar = 0x20;
1817  else
1818  TM->tmBreakChar = pOS2->usFirstCharIndex;
1819  TM->tmDefaultChar = TM->tmBreakChar - 1;
1820  }
1821 
1822  if (RealFont)
1823  {
1824  TM->tmItalic = FontGDI->OriginalItalic;
1825  TM->tmUnderlined = FALSE;
1826  TM->tmStruckOut = FALSE;
1827  }
1828  else
1829  {
1830  if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
1831  {
1832  TM->tmItalic = 0xFF;
1833  }
1834  else
1835  {
1836  TM->tmItalic = 0;
1837  }
1838  TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
1839  TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
1840  }
1841 
1842  if (!FT_IS_FIXED_WIDTH(Face))
1843  {
1844  switch (pOS2->panose[PAN_PROPORTION_INDEX])
1845  {
1846  case PAN_PROP_MONOSPACED:
1847  TM->tmPitchAndFamily = 0;
1848  break;
1849  default:
1851  break;
1852  }
1853  }
1854  else
1855  {
1856  TM->tmPitchAndFamily = 0;
1857  }
1858 
1859  switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
1860  {
1861  case PAN_FAMILY_SCRIPT:
1862  TM->tmPitchAndFamily |= FF_SCRIPT;
1863  break;
1864  case PAN_FAMILY_DECORATIVE:
1866  break;
1867 
1868  case PAN_ANY:
1869  case PAN_NO_FIT:
1871  case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
1872  /* Which is clearly not what the panose spec says. */
1873  if (TM->tmPitchAndFamily == 0) /* Fixed */
1874  {
1876  }
1877  else
1878  {
1879  switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
1880  {
1881  case PAN_ANY:
1882  case PAN_NO_FIT:
1883  default:
1885  break;
1886 
1887  case PAN_SERIF_COVE:
1888  case PAN_SERIF_OBTUSE_COVE:
1889  case PAN_SERIF_SQUARE_COVE:
1891  case PAN_SERIF_SQUARE:
1892  case PAN_SERIF_THIN:
1893  case PAN_SERIF_BONE:
1894  case PAN_SERIF_EXAGGERATED:
1895  case PAN_SERIF_TRIANGLE:
1896  TM->tmPitchAndFamily |= FF_ROMAN;
1897  break;
1898 
1899  case PAN_SERIF_NORMAL_SANS:
1900  case PAN_SERIF_OBTUSE_SANS:
1901  case PAN_SERIF_PERP_SANS:
1902  case PAN_SERIF_FLARED:
1903  case PAN_SERIF_ROUNDED:
1904  TM->tmPitchAndFamily |= FF_SWISS;
1905  break;
1906  }
1907  }
1908  break;
1909  default:
1911  }
1912 
1913  if (FT_IS_SCALABLE(Face))
1914  {
1916  }
1917  if (FT_IS_SFNT(Face))
1918  {
1920  }
1921 
1922  TM->tmCharSet = FontGDI->CharSet;
1923 }
1924 
1925 static void FASTCALL
1927  TT_OS2 *pOS2, TT_HoriHeader *pHori,
1928  FT_WinFNT_HeaderRec *pFNT)
1929 {
1930  FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
1931 }
1932 
1933 static NTSTATUS
1935  FT_UShort NameID, FT_UShort LangID);
1936 
1937 /*************************************************************
1938  * IntGetOutlineTextMetrics
1939  *
1940  */
1941 INT FASTCALL
1943  UINT Size,
1944  OUTLINETEXTMETRICW *Otm)
1945 {
1946  TT_OS2 *pOS2;
1947  TT_HoriHeader *pHori;
1948  TT_Postscript *pPost;
1949  FT_Fixed XScale, YScale;
1950  FT_WinFNT_HeaderRec Win;
1951  FT_Error Error;
1952  char *Cp;
1953  UNICODE_STRING FamilyNameW, FaceNameW, StyleNameW, FullNameW;
1954  PSHARED_FACE SharedFace = FontGDI->SharedFace;
1956  FT_Face Face = SharedFace->Face;
1957 
1958  if (Cache->OutlineRequiredSize && Size < Cache->OutlineRequiredSize)
1959  {
1960  return Cache->OutlineRequiredSize;
1961  }
1962 
1963  /* family name */
1964  RtlInitUnicodeString(&FamilyNameW, NULL);
1965  IntGetFontLocalizedName(&FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
1966 
1967  /* face name */
1968  RtlInitUnicodeString(&FaceNameW, NULL);
1970 
1971  /* style name */
1972  RtlInitUnicodeString(&StyleNameW, NULL);
1974 
1975  /* unique name (full name) */
1976  RtlInitUnicodeString(&FullNameW, NULL);
1978 
1979  if (!Cache->OutlineRequiredSize)
1980  {
1981  UINT Needed;
1982  Needed = sizeof(OUTLINETEXTMETRICW);
1983  Needed += FamilyNameW.Length + sizeof(WCHAR);
1984  Needed += FaceNameW.Length + sizeof(WCHAR);
1985  Needed += StyleNameW.Length + sizeof(WCHAR);
1986  Needed += FullNameW.Length + sizeof(WCHAR);
1987 
1988  Cache->OutlineRequiredSize = Needed;
1989  }
1990 
1991  if (Size < Cache->OutlineRequiredSize)
1992  {
1993  RtlFreeUnicodeString(&FamilyNameW);
1994  RtlFreeUnicodeString(&FaceNameW);
1995  RtlFreeUnicodeString(&StyleNameW);
1996  RtlFreeUnicodeString(&FullNameW);
1997  return Cache->OutlineRequiredSize;
1998  }
1999 
2000  XScale = Face->size->metrics.x_scale;
2001  YScale = Face->size->metrics.y_scale;
2002 
2003  IntLockFreeType();
2004  pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2005  if (NULL == pOS2)
2006  {
2008  DPRINT1("Can't find OS/2 table - not TT font?\n");
2009  RtlFreeUnicodeString(&FamilyNameW);
2010  RtlFreeUnicodeString(&FaceNameW);
2011  RtlFreeUnicodeString(&StyleNameW);
2012  RtlFreeUnicodeString(&FullNameW);
2013  return 0;
2014  }
2015 
2016  pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
2017  if (NULL == pHori)
2018  {
2020  DPRINT1("Can't find HHEA table - not TT font?\n");
2021  RtlFreeUnicodeString(&FamilyNameW);
2022  RtlFreeUnicodeString(&FaceNameW);
2023  RtlFreeUnicodeString(&StyleNameW);
2024  RtlFreeUnicodeString(&FullNameW);
2025  return 0;
2026  }
2027 
2028  pPost = FT_Get_Sfnt_Table(Face, ft_sfnt_post); /* We can live with this failing */
2029 
2030  Error = FT_Get_WinFNT_Header(Face , &Win);
2031 
2032  Otm->otmSize = Cache->OutlineRequiredSize;
2033 
2034  FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
2035 
2036  Otm->otmFiller = 0;
2038  Otm->otmfsSelection = pOS2->fsSelection;
2039  Otm->otmfsType = pOS2->fsType;
2040  Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2041  Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2042  Otm->otmItalicAngle = 0; /* POST table */
2043  Otm->otmEMSquare = Face->units_per_EM;
2044  Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
2045  Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
2046  Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
2047  Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
2048  Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
2049  Otm->otmrcFontBox.left = (FT_MulFix(Face->bbox.xMin, XScale) + 32) >> 6;
2050  Otm->otmrcFontBox.right = (FT_MulFix(Face->bbox.xMax, XScale) + 32) >> 6;
2051  Otm->otmrcFontBox.top = (FT_MulFix(Face->bbox.yMax, YScale) + 32) >> 6;
2052  Otm->otmrcFontBox.bottom = (FT_MulFix(Face->bbox.yMin, YScale) + 32) >> 6;
2053  Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
2054  Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
2055  Otm->otmMacLineGap = Otm->otmLineGap;
2056  Otm->otmusMinimumPPEM = 0; /* TT Header */
2057  Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
2058  Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
2059  Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
2060  Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
2061  Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
2062  Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
2063  Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
2064  Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
2065  Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
2066  Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
2067  if (!pPost)
2068  {
2069  Otm->otmsUnderscoreSize = 0;
2070  Otm->otmsUnderscorePosition = 0;
2071  }
2072  else
2073  {
2074  Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
2075  Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
2076  }
2077 
2079 
2080  Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
2081 
2082  /* family name */
2083  Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
2084  wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
2085  Cp += FamilyNameW.Length + sizeof(WCHAR);
2086 
2087  /* face name */
2088  Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
2089  wcscpy((WCHAR*) Cp, FaceNameW.Buffer);
2090  Cp += FaceNameW.Length + sizeof(WCHAR);
2091 
2092  /* style name */
2093  Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
2094  wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
2095  Cp += StyleNameW.Length + sizeof(WCHAR);
2096 
2097  /* unique name (full name) */
2098  Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
2099  wcscpy((WCHAR*) Cp, FullNameW.Buffer);
2100  Cp += FullNameW.Length + sizeof(WCHAR);
2101 
2102  ASSERT(Cp - (char*)Otm == Cache->OutlineRequiredSize);
2103 
2104  RtlFreeUnicodeString(&FamilyNameW);
2105  RtlFreeUnicodeString(&FaceNameW);
2106  RtlFreeUnicodeString(&StyleNameW);
2107  RtlFreeUnicodeString(&FullNameW);
2108 
2109  return Cache->OutlineRequiredSize;
2110 }
2111 
2112 static PFONTGDI FASTCALL
2114 {
2116  PFONT_ENTRY CurrentEntry;
2117  ANSI_STRING EntryFaceNameA;
2118  UNICODE_STRING EntryFaceNameW;
2119  FONTGDI *FontGDI;
2120  NTSTATUS status;
2121 
2122  for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
2123  {
2124  CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2125 
2126  FontGDI = CurrentEntry->Font;
2127  ASSERT(FontGDI);
2128 
2129  RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
2130  status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2131  if (!NT_SUCCESS(status))
2132  {
2133  break;
2134  }
2135 
2136  if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2137  {
2138  EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2139  EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2140  }
2141 
2142  if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE))
2143  {
2144  RtlFreeUnicodeString(&EntryFaceNameW);
2145  return FontGDI;
2146  }
2147 
2148  RtlFreeUnicodeString(&EntryFaceNameW);
2149  }
2150 
2151  return NULL;
2152 }
2153 
2154 static PFONTGDI FASTCALL
2156 {
2157  PPROCESSINFO Win32Process;
2158  PFONTGDI Font;
2159 
2160  /* Search the process local list.
2161  We do not have to search the 'Mem' list, since those fonts are linked in the PrivateFontListHead */
2162  Win32Process = PsGetCurrentProcessWin32Process();
2163  IntLockProcessPrivateFonts(Win32Process);
2164  Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
2165  IntUnLockProcessPrivateFonts(Win32Process);
2166  if (NULL != Font)
2167  {
2168  return Font;
2169  }
2170 
2171  /* Search the global list */
2173  Font = FindFaceNameInList(FaceName, &g_FontListHead);
2175 
2176  return Font;
2177 }
2178 
2179 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
2180 static BYTE
2182 {
2183  /* FIXME: Add more and fix if wrong */
2184  switch (PRIMARYLANGID(LangID))
2185  {
2186  case LANG_CHINESE:
2187  switch (SUBLANGID(LangID))
2188  {
2190  return CHINESEBIG5_CHARSET;
2192  default:
2193  break;
2194  }
2195  return GB2312_CHARSET;
2196 
2197  case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
2198  case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
2199  return EASTEUROPE_CHARSET;
2200 
2201  case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
2202  case LANG_SERBIAN: case LANG_UKRAINIAN:
2203  return RUSSIAN_CHARSET;
2204 
2205  case LANG_ARABIC: return ARABIC_CHARSET;
2206  case LANG_GREEK: return GREEK_CHARSET;
2207  case LANG_HEBREW: return HEBREW_CHARSET;
2208  case LANG_JAPANESE: return SHIFTJIS_CHARSET;
2209  case LANG_KOREAN: return JOHAB_CHARSET;
2210  case LANG_TURKISH: return TURKISH_CHARSET;
2211  case LANG_THAI: return THAI_CHARSET;
2212  case LANG_LATVIAN: return BALTIC_CHARSET;
2213  case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
2214 
2215  case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
2216  case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
2217  case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
2218  case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
2219  case LANG_SWEDISH: default:
2220  return ANSI_CHARSET;
2221  }
2222 }
2223 
2224 static void
2226 {
2227  BYTE b, *pb = pvData;
2228  Size /= 2;
2229  while (Size-- > 0)
2230  {
2231  b = pb[0];
2232  pb[0] = pb[1];
2233  pb[1] = b;
2234  ++pb; ++pb;
2235  }
2236 }
2237 
2238 static NTSTATUS
2240 {
2242  UNICODE_STRING Tmp;
2243 
2245  if (Tmp.Buffer)
2246  {
2247  Tmp.MaximumLength = Source->MaximumLength;
2248  Tmp.Length = 0;
2249  RtlCopyUnicodeString(&Tmp, Source);
2250 
2251  Destination->MaximumLength = Tmp.MaximumLength;
2252  Destination->Length = Tmp.Length;
2253  Destination->Buffer = Tmp.Buffer;
2254 
2255  Status = STATUS_SUCCESS;
2256  }
2257 
2258  return Status;
2259 }
2260 
2261 static NTSTATUS
2263  FT_UShort NameID, FT_UShort LangID)
2264 {
2265  FT_SfntName Name;
2266  INT i, Count, BestIndex, Score, BestScore;
2267  FT_Error Error;
2269  ANSI_STRING AnsiName;
2271  FT_Face Face = SharedFace->Face;
2272 
2273  RtlFreeUnicodeString(pNameW);
2274 
2275  /* select cache */
2276  if (PRIMARYLANGID(LangID) == LANG_ENGLISH)
2277  {
2278  Cache = &SharedFace->EnglishUS;
2279  }
2280  else
2281  {
2282  Cache = &SharedFace->UserLanguage;
2283  }
2284 
2285  /* use cache if available */
2286  if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer)
2287  {
2288  return DuplicateUnicodeString(&Cache->FontFamily, pNameW);
2289  }
2290  if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer)
2291  {
2292  return DuplicateUnicodeString(&Cache->FullName, pNameW);
2293  }
2294 
2295  BestIndex = -1;
2296  BestScore = 0;
2297 
2298  Count = FT_Get_Sfnt_Name_Count(Face);
2299  for (i = 0; i < Count; ++i)
2300  {
2301  Error = FT_Get_Sfnt_Name(Face, i, &Name);
2302  if (Error)
2303  {
2304  continue; /* failure */
2305  }
2306 
2307  if (Name.name_id != NameID)
2308  {
2309  continue; /* mismatched */
2310  }
2311 
2312  if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
2313  (Name.encoding_id != TT_MS_ID_UNICODE_CS &&
2314  Name.encoding_id != TT_MS_ID_SYMBOL_CS))
2315  {
2316  continue; /* not Microsoft Unicode name */
2317  }
2318 
2319  if (Name.string == NULL || Name.string_len == 0 ||
2320  (Name.string[0] == 0 && Name.string[1] == 0))
2321  {
2322  continue; /* invalid string */
2323  }
2324 
2325  if (Name.language_id == LangID)
2326  {
2327  Score = 30;
2328  BestIndex = i;
2329  break; /* best match */
2330  }
2331  else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID))
2332  {
2333  Score = 20;
2334  }
2335  else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH)
2336  {
2337  Score = 10;
2338  }
2339  else
2340  {
2341  Score = 0;
2342  }
2343 
2344  if (Score > BestScore)
2345  {
2346  BestScore = Score;
2347  BestIndex = i;
2348  }
2349  }
2350 
2351  if (BestIndex >= 0)
2352  {
2353  /* store the best name */
2354  Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
2355  if (!Error)
2356  {
2357  /* NOTE: Name.string is not null-terminated */
2358  UNICODE_STRING Tmp;
2359  Tmp.Buffer = (PWCH)Name.string;
2360  Tmp.Length = Tmp.MaximumLength = Name.string_len;
2361 
2362  pNameW->Length = 0;
2363  pNameW->MaximumLength = Name.string_len + sizeof(WCHAR);
2365 
2366  if (pNameW->Buffer)
2367  {
2368  Status = RtlAppendUnicodeStringToString(pNameW, &Tmp);
2369  if (Status == STATUS_SUCCESS)
2370  {
2371  /* Convert UTF-16 big endian to little endian */
2372  SwapEndian(pNameW->Buffer, pNameW->Length);
2373  }
2374  }
2375  else
2376  {
2378  }
2379  }
2380  }
2381 
2382  if (!NT_SUCCESS(Status))
2383  {
2384  /* defaulted */
2385  if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
2386  {
2387  RtlInitAnsiString(&AnsiName, Face->style_name);
2388  Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2389  }
2390  else
2391  {
2392  RtlInitAnsiString(&AnsiName, Face->family_name);
2393  Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2394  }
2395  }
2396 
2397  if (NT_SUCCESS(Status))
2398  {
2399  /* make cache */
2400  if (NameID == TT_NAME_ID_FONT_FAMILY)
2401  {
2403  IntLockFreeType();
2404  if (!Cache->FontFamily.Buffer)
2405  DuplicateUnicodeString(pNameW, &Cache->FontFamily);
2407  }
2408  else if (NameID == TT_NAME_ID_FULL_NAME)
2409  {
2411  IntLockFreeType();
2412  if (!Cache->FullName.Buffer)
2413  DuplicateUnicodeString(pNameW, &Cache->FullName);
2415  }
2416  }
2417 
2418  return Status;
2419 }
2420 
2421 static void FASTCALL
2423  LPCWSTR FullName, PFONTGDI FontGDI)
2424 {
2425  ANSI_STRING StyleA;
2426  UNICODE_STRING StyleW;
2427  TT_OS2 *pOS2;
2428  FONTSIGNATURE fs;
2429  CHARSETINFO CharSetInfo;
2430  unsigned i, Size;
2431  OUTLINETEXTMETRICW *Otm;
2432  LOGFONTW *Lf;
2433  TEXTMETRICW *TM;
2434  NEWTEXTMETRICW *Ntm;
2435  DWORD fs0;
2436  NTSTATUS status;
2437  PSHARED_FACE SharedFace = FontGDI->SharedFace;
2438  FT_Face Face = SharedFace->Face;
2439  UNICODE_STRING NameW;
2440 
2441  RtlInitUnicodeString(&NameW, NULL);
2442  RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
2443  Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2445  if (!Otm)
2446  {
2447  return;
2448  }
2449  Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2450  if (!Size)
2451  {
2453  return;
2454  }
2455 
2456  Lf = &Info->EnumLogFontEx.elfLogFont;
2457  TM = &Otm->otmTextMetrics;
2458 
2459  Lf->lfHeight = TM->tmHeight;
2460  Lf->lfWidth = TM->tmAveCharWidth;
2461  Lf->lfWeight = TM->tmWeight;
2462  Lf->lfItalic = TM->tmItalic;
2463  Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
2464  Lf->lfCharSet = TM->tmCharSet;
2467  Lf->lfQuality = PROOF_QUALITY;
2468 
2469  Ntm = &Info->NewTextMetricEx.ntmTm;
2470  Ntm->tmHeight = TM->tmHeight;
2471  Ntm->tmAscent = TM->tmAscent;
2472  Ntm->tmDescent = TM->tmDescent;
2475  Ntm->tmAveCharWidth = TM->tmAveCharWidth;
2476  Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
2477  Ntm->tmWeight = TM->tmWeight;
2478  Ntm->tmOverhang = TM->tmOverhang;
2481  Ntm->tmFirstChar = TM->tmFirstChar;
2482  Ntm->tmLastChar = TM->tmLastChar;
2483  Ntm->tmDefaultChar = TM->tmDefaultChar;
2484  Ntm->tmBreakChar = TM->tmBreakChar;
2485  Ntm->tmItalic = TM->tmItalic;
2486  Ntm->tmUnderlined = TM->tmUnderlined;
2487  Ntm->tmStruckOut = TM->tmStruckOut;
2489  Ntm->tmCharSet = TM->tmCharSet;
2490  Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
2491 
2492  if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
2493 
2494  if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
2495 
2496  Ntm->ntmSizeEM = Otm->otmEMSquare;
2497  Ntm->ntmCellHeight = Otm->otmEMSquare;
2498  Ntm->ntmAvgWidth = 0;
2499 
2500  Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
2501  ? TRUETYPE_FONTTYPE : 0);
2502 
2503  if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
2504  Info->FontType |= RASTER_FONTTYPE;
2505 
2506 
2507  /* face name */
2508  if (!FaceName)
2509  FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
2510 
2511  RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
2512 
2513  /* full name */
2514  if (!FullName)
2515  FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName);
2516 
2518  sizeof(Info->EnumLogFontEx.elfFullName),
2519  FullName);
2520 
2522 
2523  RtlInitAnsiString(&StyleA, Face->style_name);
2524  StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
2525  StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
2526  status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
2527  if (!NT_SUCCESS(status))
2528  {
2529  return;
2530  }
2532 
2533  IntLockFreeType();
2534  pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2535 
2536  if (!pOS2)
2537  {
2539  return;
2540  }
2541 
2542  fs.fsCsb[0] = pOS2->ulCodePageRange1;
2543  fs.fsCsb[1] = pOS2->ulCodePageRange2;
2544  fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2545  fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2546  fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2547  fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2548 
2549  if (0 == pOS2->version)
2550  {
2551  FT_UInt Dummy;
2552 
2553  if (FT_Get_First_Char(Face, &Dummy) < 0x100)
2554  fs.fsCsb[0] |= FS_LATIN1;
2555  else
2556  fs.fsCsb[0] |= FS_SYMBOL;
2557  }
2559 
2560  if (fs.fsCsb[0] == 0)
2561  {
2562  /* Let's see if we can find any interesting cmaps */
2563  for (i = 0; i < (UINT)Face->num_charmaps; i++)
2564  {
2565  switch (Face->charmaps[i]->encoding)
2566  {
2567  case FT_ENCODING_UNICODE:
2568  case FT_ENCODING_APPLE_ROMAN:
2569  fs.fsCsb[0] |= FS_LATIN1;
2570  break;
2571  case FT_ENCODING_MS_SYMBOL:
2572  fs.fsCsb[0] |= FS_SYMBOL;
2573  break;
2574  default:
2575  break;
2576  }
2577  }
2578  }
2579 
2580  for (i = 0; i < MAXTCIINDEX; i++)
2581  {
2582  fs0 = 1L << i;
2583  if (fs.fsCsb[0] & fs0)
2584  {
2585  if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
2586  {
2587  CharSetInfo.ciCharset = DEFAULT_CHARSET;
2588  }
2589  if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
2590  {
2591  if (g_ElfScripts[i])
2593  else
2594  {
2595  DPRINT1("Unknown elfscript for bit %u\n", i);
2596  }
2597  }
2598  }
2599  }
2600  Info->NewTextMetricEx.ntmFontSig = fs;
2601 }
2602 
2603 static int FASTCALL
2605 {
2606  DWORD i;
2607  UNICODE_STRING InfoFaceName;
2608 
2609  for (i = 0; i < InfoEntries; i++)
2610  {
2611  RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
2612  if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE))
2613  {
2614  return i;
2615  }
2616  }
2617 
2618  return -1;
2619 }
2620 
2621 static BOOLEAN FASTCALL
2623  PFONTFAMILYINFO Info, DWORD InfoEntries)
2624 {
2625  UNICODE_STRING LogFontFaceName;
2626 
2627  RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
2628  if (0 != LogFontFaceName.Length &&
2629  !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE))
2630  {
2631  return FALSE;
2632  }
2633 
2634  return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
2635 }
2636 
2637 static BOOL FASTCALL
2639  PFONTFAMILYINFO Info, DWORD InfoCount)
2640 {
2641  LPLOGFONTW plf1 = &InfoEntry->EnumLogFontEx.elfLogFont;
2642  LPWSTR pFullName1 = InfoEntry->EnumLogFontEx.elfFullName;
2643  LPWSTR pFullName2;
2644  DWORD i;
2645 
2646  for (i = 0; i < InfoCount; ++i)
2647  {
2648  LPLOGFONTW plf2 = &Info[i].EnumLogFontEx.elfLogFont;
2649  if (plf1->lfCharSet != plf2->lfCharSet)
2650  continue;
2651 
2652  pFullName2 = Info[i].EnumLogFontEx.elfFullName;
2653  if (_wcsicmp(pFullName1, pFullName2) != 0)
2654  continue;
2655 
2656  return TRUE;
2657  }
2658  return FALSE;
2659 }
2660 
2661 static BOOLEAN FASTCALL
2664  DWORD *pCount,
2665  DWORD MaxCount,
2666  PLIST_ENTRY Head)
2667 {
2669  PFONT_ENTRY CurrentEntry;
2670  FONTGDI *FontGDI;
2671  FONTFAMILYINFO InfoEntry;
2672  DWORD Count = *pCount;
2673 
2674  for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
2675  {
2676  CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2677  FontGDI = CurrentEntry->Font;
2678  ASSERT(FontGDI);
2679 
2680  if (LogFont->lfCharSet != DEFAULT_CHARSET &&
2681  LogFont->lfCharSet != FontGDI->CharSet)
2682  {
2683  continue;
2684  }
2685 
2686  if (LogFont->lfFaceName[0] == UNICODE_NULL)
2687  {
2688  if (Count < MaxCount)
2689  {
2690  FontFamilyFillInfo(&Info[Count], NULL, NULL, FontGDI);
2691  }
2692  Count++;
2693  continue;
2694  }
2695 
2696  FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
2697 
2698  if (_wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0 &&
2699  _wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfFullName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0)
2700  {
2701  continue;
2702  }
2703 
2704  if (!FontFamilyFound(&InfoEntry, Info, min(Count, MaxCount)))
2705  {
2706  if (Count < MaxCount)
2707  {
2708  RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
2709  }
2710  Count++;
2711  }
2712  }
2713 
2714  *pCount = Count;
2715 
2716  return TRUE;
2717 }
2718 
2719 static BOOLEAN FASTCALL
2722  DWORD *pCount,
2723  DWORD MaxCount)
2724 {
2725  PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead;
2726  PFONTSUBST_ENTRY pCurrentEntry;
2727  PUNICODE_STRING pFromW;
2728  FONTGDI *FontGDI;
2729  LOGFONTW lf = *LogFont;
2730  UNICODE_STRING NameW;
2731 
2732  for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
2733  {
2734  pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
2735 
2736  pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
2737  if (LogFont->lfFaceName[0] != UNICODE_NULL)
2738  {
2739  if (!FontFamilyInclude(LogFont, pFromW, Info, min(*pCount, MaxCount)))
2740  continue; /* mismatch */
2741  }
2742 
2744  SubstituteFontRecurse(&lf);
2745 
2746  RtlInitUnicodeString(&NameW, lf.lfFaceName);
2747  FontGDI = FindFaceNameInLists(&NameW);
2748  if (FontGDI == NULL)
2749  {
2750  continue; /* no real font */
2751  }
2752 
2753  if (*pCount < MaxCount)
2754  {
2755  FontFamilyFillInfo(&Info[*pCount], pFromW->Buffer, NULL, FontGDI);
2756  }
2757  (*pCount)++;
2758  }
2759 
2760  return TRUE;
2761 }
2762 
2763 BOOL
2764 FASTCALL
2766 {
2767  if ( lprs )
2768  {
2769  lprs->nSize = sizeof(RASTERIZER_STATUS);
2770  lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
2771  lprs->nLanguageID = gusLanguageID;
2772  return TRUE;
2773  }
2775  return FALSE;
2776 }
2777 
2778 static
2779 BOOL
2781  PMATRIX pmx1,
2782  PMATRIX pmx2)
2783 {
2784  return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
2785  FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
2786  FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
2787  FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
2788 }
2789 
2792  FT_Face Face,
2793  INT GlyphIndex,
2794  INT Height,
2795  FT_Render_Mode RenderMode,
2796  PMATRIX pmx)
2797 {
2798  PLIST_ENTRY CurrentEntry;
2799  PFONT_CACHE_ENTRY FontEntry;
2800 
2802 
2803  for (CurrentEntry = g_FontCacheListHead.Flink;
2804  CurrentEntry != &g_FontCacheListHead;
2805  CurrentEntry = CurrentEntry->Flink)
2806  {
2807  FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
2808  if ((FontEntry->Face == Face) &&
2809  (FontEntry->GlyphIndex == GlyphIndex) &&
2810  (FontEntry->Height == Height) &&
2811  (FontEntry->RenderMode == RenderMode) &&
2812  (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2813  break;
2814  }
2815 
2816  if (CurrentEntry == &g_FontCacheListHead)
2817  {
2818  return NULL;
2819  }
2820 
2821  RemoveEntryList(CurrentEntry);
2822  InsertHeadList(&g_FontCacheListHead, CurrentEntry);
2823  return FontEntry->BitmapGlyph;
2824 }
2825 
2826 /* no cache */
2829  FT_Face Face,
2830  FT_GlyphSlot GlyphSlot,
2831  FT_Render_Mode RenderMode)
2832 {
2833  FT_Glyph Glyph;
2834  INT error;
2835  FT_Bitmap AlignedBitmap;
2836  FT_BitmapGlyph BitmapGlyph;
2837 
2838  error = FT_Get_Glyph(GlyphSlot, &Glyph);
2839  if (error)
2840  {
2841  DPRINT1("Failure getting glyph.\n");
2842  return NULL;
2843  }
2844 
2845  error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2846  if (error)
2847  {
2848  FT_Done_Glyph(Glyph);
2849  DPRINT1("Failure rendering glyph.\n");
2850  return NULL;
2851  }
2852 
2853  BitmapGlyph = (FT_BitmapGlyph)Glyph;
2854  FT_Bitmap_New(&AlignedBitmap);
2855  if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2856  {
2857  DPRINT1("Conversion failed\n");
2858  FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2859  return NULL;
2860  }
2861 
2862  FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2863  BitmapGlyph->bitmap = AlignedBitmap;
2864 
2865  return BitmapGlyph;
2866 }
2867 
2870  FT_Face Face,
2871  INT GlyphIndex,
2872  INT Height,
2873  PMATRIX pmx,
2874  FT_GlyphSlot GlyphSlot,
2875  FT_Render_Mode RenderMode)
2876 {
2877  FT_Glyph GlyphCopy;
2878  INT error;
2879  PFONT_CACHE_ENTRY NewEntry;
2880  FT_Bitmap AlignedBitmap;
2881  FT_BitmapGlyph BitmapGlyph;
2882 
2884 
2885  error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2886  if (error)
2887  {
2888  DPRINT1("Failure caching glyph.\n");
2889  return NULL;
2890  };
2891 
2892  error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2893  if (error)
2894  {
2895  FT_Done_Glyph(GlyphCopy);
2896  DPRINT1("Failure rendering glyph.\n");
2897  return NULL;
2898  };
2899 
2901  if (!NewEntry)
2902  {
2903  DPRINT1("Alloc failure caching glyph.\n");
2904  FT_Done_Glyph(GlyphCopy);
2905  return NULL;
2906  }
2907 
2908  BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2909  FT_Bitmap_New(&AlignedBitmap);
2910  if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2911  {
2912  DPRINT1("Conversion failed\n");
2913  ExFreePoolWithTag(NewEntry, TAG_FONT);
2914  FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
2915  FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2916  return NULL;
2917  }
2918 
2919  FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2920  BitmapGlyph->bitmap = AlignedBitmap;
2921 
2922  NewEntry->GlyphIndex = GlyphIndex;
2923  NewEntry->Face = Face;
2924  NewEntry->BitmapGlyph = BitmapGlyph;
2925  NewEntry->Height = Height;
2926  NewEntry->RenderMode = RenderMode;
2927  NewEntry->mxWorldToDevice = *pmx;
2928 
2929  InsertHeadList(&g_FontCacheListHead, &NewEntry->ListEntry);
2931  {
2932  NewEntry = CONTAINING_RECORD(g_FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
2933  RemoveCachedEntry(NewEntry);
2934  }
2935 
2936  return BitmapGlyph;
2937 }
2938 
2939 
2941 {
2942  pt->x.value = vec->x >> 6;
2943  pt->x.fract = (vec->x & 0x3f) << 10;
2944  pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2945  pt->y.value = vec->y >> 6;
2946  pt->y.fract = (vec->y & 0x3f) << 10;
2947  pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2948 }
2949 
2950 /*
2951  This function builds an FT_Fixed from a float. It puts the integer part
2952  in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2953  It fails if the integer part of the float number is greater than SHORT_MAX.
2954 */
2955 static __inline FT_Fixed FT_FixedFromFloat(float f)
2956 {
2957  short value = f;
2958  unsigned short fract = (f - value) * 0xFFFF;
2959  return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2960 }
2961 
2962 /*
2963  This function builds an FT_Fixed from a FIXED. It simply put f.value
2964  in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2965 */
2967 {
2968  return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2969 }
2970 
2971 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2972 {
2973  TTPOLYGONHEADER *pph;
2974  TTPOLYCURVE *ppc;
2975  int needed = 0, point = 0, contour, first_pt;
2976  unsigned int pph_start, cpfx;
2977  DWORD type;
2978 
2979  for (contour = 0; contour < outline->n_contours; contour++)
2980  {
2981  /* Ignore contours containing one point */
2982  if (point == outline->contours[contour])
2983  {
2984  point++;
2985  continue;
2986  }
2987 
2988  pph_start = needed;
2989  pph = (TTPOLYGONHEADER *)(buf + needed);
2990  first_pt = point;
2991  if (buf)
2992  {
2993  pph->dwType = TT_POLYGON_TYPE;
2994  FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2995  }
2996  needed += sizeof(*pph);
2997  point++;
2998  while (point <= outline->contours[contour])
2999  {
3000  ppc = (TTPOLYCURVE *)(buf + needed);
3001  type = outline->tags[point] & FT_Curve_Tag_On ?
3003  cpfx = 0;
3004  do
3005  {
3006  if (buf)
3007  FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3008  cpfx++;
3009  point++;
3010  } while (point <= outline->contours[contour] &&
3011  (outline->tags[point] & FT_Curve_Tag_On) ==
3012  (outline->tags[point-1] & FT_Curve_Tag_On));
3013  /* At the end of a contour Windows adds the start point, but
3014  only for Beziers */
3015  if (point > outline->contours[contour] &&
3016  !(outline->tags[point-1] & FT_Curve_Tag_On))
3017  {
3018  if (buf)
3019  FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3020  cpfx++;
3021  }
3022  else if (point <= outline->contours[contour] &&
3023  outline->tags[point] & FT_Curve_Tag_On)
3024  {
3025  /* add closing pt for bezier */
3026  if (buf)
3027  FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3028  cpfx++;
3029  point++;
3030  }
3031  if (buf)
3032  {
3033  ppc->wType = type;
3034  ppc->cpfx = cpfx;
3035  }
3036  needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3037  }
3038  if (buf)
3039  pph->cb = needed - pph_start;
3040  }
3041  return needed;
3042 }
3043 
3044 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3045 {
3046  /* Convert the quadratic Beziers to cubic Beziers.
3047  The parametric eqn for a cubic Bezier is, from PLRM:
3048  r(t) = at^3 + bt^2 + ct + r0
3049  with the control points:
3050  r1 = r0 + c/3
3051  r2 = r1 + (c + b)/3
3052  r3 = r0 + c + b + a
3053 
3054  A quadratic Bezier has the form:
3055  p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3056 
3057  So equating powers of t leads to:
3058  r1 = 2/3 p1 + 1/3 p0
3059  r2 = 2/3 p1 + 1/3 p2
3060  and of course r0 = p0, r3 = p2
3061  */
3062  int contour, point = 0, first_pt;
3063  TTPOLYGONHEADER *pph;
3064  TTPOLYCURVE *ppc;
3065  DWORD pph_start, cpfx, type;
3066  FT_Vector cubic_control[4];
3067  unsigned int needed = 0;
3068 
3069  for (contour = 0; contour < outline->n_contours; contour++)
3070  {
3071  pph_start = needed;
3072  pph = (TTPOLYGONHEADER *)(buf + needed);
3073  first_pt = point;
3074  if (buf)
3075  {
3076  pph->dwType = TT_POLYGON_TYPE;
3077  FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3078  }
3079  needed += sizeof(*pph);
3080  point++;
3081  while (point <= outline->contours[contour])
3082  {
3083  ppc = (TTPOLYCURVE *)(buf + needed);
3084  type = outline->tags[point] & FT_Curve_Tag_On ?
3086  cpfx = 0;
3087  do
3088  {
3089  if (type == TT_PRIM_LINE)
3090  {
3091  if (buf)
3092  FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3093  cpfx++;
3094  point++;
3095  }
3096  else
3097  {
3098  /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3099  so cpfx = 3n */
3100 
3101  /* FIXME: Possible optimization in endpoint calculation
3102  if there are two consecutive curves */
3103  cubic_control[0] = outline->points[point-1];
3104  if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3105  {
3106  cubic_control[0].x += outline->points[point].x + 1;
3107  cubic_control[0].y += outline->points[point].y + 1;
3108  cubic_control[0].x >>= 1;
3109  cubic_control[0].y >>= 1;
3110  }
3111  if (point+1 > outline->contours[contour])
3112  cubic_control[3] = outline->points[first_pt];
3113  else
3114  {
3115  cubic_control[3] = outline->points[point+1];
3116  if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3117  {
3118  cubic_control[3].x += outline->points[point].x + 1;
3119  cubic_control[3].y += outline->points[point].y + 1;
3120  cubic_control[3].x >>= 1;
3121  cubic_control[3].y >>= 1;
3122  }
3123  }
3124  /* r1 = 1/3 p0 + 2/3 p1
3125  r2 = 1/3 p2 + 2/3 p1 */
3126  cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3127  cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3128  cubic_control[2] = cubic_control[1];
3129  cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3130  cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3131  cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3132  cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3133  if (buf)
3134  {
3135  FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3136  FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3137  FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3138  }
3139  cpfx += 3;
3140  point++;
3141  }
3142  } while (point <= outline->contours[contour] &&
3143  (outline->tags[point] & FT_Curve_Tag_On) ==
3144  (outline->tags[point-1] & FT_Curve_Tag_On));
3145  /* At the end of a contour Windows adds the start point,
3146  but only for Beziers and we've already done that.
3147  */
3148  if (point <= outline->contours[contour] &&
3149  outline->tags[point] & FT_Curve_Tag_On)
3150  {
3151  /* This is the closing pt of a bezier, but we've already
3152  added it, so just inc point and carry on */
3153  point++;
3154  }
3155  if (buf)
3156  {
3157  ppc->wType = type;
3158  ppc->cpfx = cpfx;
3159  }
3160  needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3161  }
3162  if (buf)
3163  pph->cb = needed - pph_start;
3164  }
3165  return needed;
3166 }
3167 
3168 static FT_Error
3169 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
3170 {
3171  FT_Error error;
3172  FT_Size_RequestRec req;
3173  FT_Face face = FontGDI->SharedFace->Face;
3174  TT_OS2 *pOS2;
3175  TT_HoriHeader *pHori;
3176  FT_WinFNT_HeaderRec WinFNT;
3177  LONG Ascent, Descent, Sum, EmHeight64;
3178 
3179  lfWidth = abs(lfWidth);
3180  if (lfHeight == 0)
3181  {
3182  if (lfWidth == 0)
3183  {
3184  DPRINT("lfHeight and lfWidth are zero.\n");
3185  lfHeight = -16;
3186  }
3187  else
3188  {
3189  lfHeight = lfWidth;
3190  }
3191  }
3192 
3193  if (lfHeight == -1)
3194  lfHeight = -2;
3195 
3197  pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
3198  pHori = (TT_HoriHeader *)FT_Get_Sfnt_Table(face, FT_SFNT_HHEA);
3199 
3200  if (!pOS2 || !pHori)
3201  {
3202  error = FT_Get_WinFNT_Header(face, &WinFNT);
3203  if (error)
3204  return error;
3205 
3206  FontGDI->tmHeight = WinFNT.pixel_height;
3207  FontGDI->tmAscent = WinFNT.ascent;
3208  FontGDI->tmDescent = FontGDI->tmHeight - FontGDI->tmAscent;
3209  FontGDI->tmInternalLeading = WinFNT.internal_leading;
3210  FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3211  FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3212  FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3213  FontGDI->Magic = FONTGDI_MAGIC;
3214 
3216  req.width = 0;
3217  req.height = (FT_Long)(FontGDI->EmHeight << 6);
3218  req.horiResolution = 0;
3219  req.vertResolution = 0;
3220  return FT_Request_Size(face, &req);
3221  }
3222 
3223  if (lfHeight > 0)
3224  {
3225  /* case (A): lfHeight is positive */
3226  Sum = pOS2->usWinAscent + pOS2->usWinDescent;
3227  if (Sum == 0)
3228  {
3229  Ascent = pHori->Ascender;
3230  Descent = -pHori->Descender;
3231  Sum = Ascent + Descent;
3232  }
3233  else
3234  {
3235  Ascent = pOS2->usWinAscent;
3236  Descent = pOS2->usWinDescent;
3237  }
3238 
3239  FontGDI->tmAscent = FT_MulDiv(lfHeight, Ascent, Sum);
3240  FontGDI->tmDescent = FT_MulDiv(lfHeight, Descent, Sum);
3241  FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3242  FontGDI->tmInternalLeading = FontGDI->tmHeight - FT_MulDiv(lfHeight, face->units_per_EM, Sum);
3243  }
3244  else if (lfHeight < 0)
3245  {
3246  /* case (B): lfHeight is negative */
3247  FontGDI->tmAscent = FT_MulDiv(-lfHeight, pOS2->usWinAscent, face->units_per_EM);
3248  FontGDI->tmDescent = FT_MulDiv(-lfHeight, pOS2->usWinDescent, face->units_per_EM);
3249  FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3250  FontGDI->tmInternalLeading = FontGDI->tmHeight + lfHeight;
3251  }
3252 
3253  FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3254  FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3255  FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3256  FontGDI->Magic = FONTGDI_MAGIC;
3257 
3258  if (lfHeight > 0)
3259  EmHeight64 = (FontGDI->EmHeight << 6) + 31;
3260  else
3261  EmHeight64 = (FontGDI->EmHeight << 6);
3262 
3264  req.width = 0;
3265  req.height = EmHeight64;
3266  req.horiResolution = 0;
3267  req.vertResolution = 0;
3268  return FT_Request_Size(face, &req);
3269 }
3270 
3271 BOOL
3272 FASTCALL
3274  PTEXTOBJ TextObj,
3275  PFONTGDI FontGDI,
3276  BOOL bDoLock)
3277 {
3278  FT_Face face;
3279  INT error, n;
3280  FT_CharMap charmap, found;
3281  LOGFONTW *plf;
3282 
3283  if (bDoLock)
3284  IntLockFreeType();
3285 
3286  face = FontGDI->SharedFace->Face;
3287  if (face->charmap == NULL)
3288  {
3289  DPRINT("WARNING: No charmap selected!\n");
3290  DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3291 
3292  found = NULL;
3293  for (n = 0; n < face->num_charmaps; n++)
3294  {
3295  charmap = face->charmaps[n];
3296  if (charmap->encoding == FT_ENCODING_UNICODE)
3297  {
3298  found = charmap;
3299  break;
3300  }
3301  }
3302  if (!found)
3303  {
3304  for (n = 0; n < face->num_charmaps; n++)
3305  {
3306  charmap = face->charmaps[n];
3307  if (charmap->encoding == FT_ENCODING_MS_SYMBOL)
3308  {
3309  found = charmap;
3310  break;
3311  }
3312  }
3313  }
3314  if (!found)
3315  {
3316  DPRINT1("WARNING: Could not find desired charmap!\n");
3317  }
3318  else
3319  {
3320  DPRINT("Found charmap encoding: %i\n", found->encoding);
3321  error = FT_Set_Charmap(face, found);
3322  if (error)
3323  {
3324  DPRINT1("WARNING: Could not set the charmap!\n");
3325  }
3326  }
3327  }
3328 
3329  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3330 
3331  error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
3332 
3333  if (bDoLock)
3335 
3336  if (error)
3337  {
3338  DPRINT1("Error in setting pixel sizes: %d\n", error);
3339  return FALSE;
3340  }
3341 
3342  return TRUE;
3343 }
3344 
3345 static inline FT_UInt FASTCALL
3347 {
3348  FT_UInt ret;
3349 
3350  if (glyph < 0x100) glyph += 0xf000;
3351  /* there are a number of old pre-Unicode "broken" TTFs, which
3352  do have symbols at U+00XX instead of U+f0XX */
3353  if (!(ret = FT_Get_Char_Index(ft_face, glyph)))
3354  ret = FT_Get_Char_Index(ft_face, glyph - 0xf000);
3355 
3356  return ret;
3357 }
3358 
3359 static inline FT_UInt FASTCALL
3361 {
3362  FT_UInt ret;
3363 
3364  if (face_has_symbol_charmap(ft_face))
3365  {
3366  ret = get_glyph_index_symbol(ft_face, glyph);
3367  if (ret != 0)
3368  return ret;
3369  }
3370 
3371  return FT_Get_Char_Index(ft_face, glyph);
3372 }
3373 
3374 static inline FT_UInt FASTCALL
3376 {
3377  FT_UInt glyph_index;
3378  if (flags & indexed_flag)
3379  {
3380  glyph_index = code;
3381  }
3382  else
3383  {
3384  glyph_index = get_glyph_index(face, code);
3385  }
3386  return glyph_index;
3387 }
3388 
3389 /*
3390  * Based on WineEngGetGlyphOutline
3391  *
3392  */
3393 ULONG
3394 FASTCALL
3396  PDC dc,
3397  WCHAR wch,
3398  UINT iFormat,
3399  LPGLYPHMETRICS pgm,
3400  ULONG cjBuf,
3401  PVOID pvBuf,
3402  LPMAT2 pmat2,
3403  BOOL bIgnoreRotation)
3404 {
3405  static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3406  PDC_ATTR pdcattr;
3407  PTEXTOBJ TextObj;
3408  PFONTGDI FontGDI;
3409  HFONT hFont = 0;
3410  GLYPHMETRICS gm;
3411  ULONG Size;
3412  FT_Face ft_face;
3413  FT_UInt glyph_index;
3414  DWORD width, height, pitch, needed = 0;
3415  FT_Bitmap ft_bitmap;
3416  FT_Error error;
3417  INT left, right, top = 0, bottom = 0;
3418  FT_Angle angle = 0;
3420  FLOAT eM11, widthRatio = 1.0;
3421  FT_Matrix transMat = identityMat;
3422  BOOL needsTransform = FALSE;
3423  INT orientation;
3424  LONG aveWidth;
3425  INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3426  OUTLINETEXTMETRICW *potm;
3427  XFORM xForm;
3428  LOGFONTW *plf;
3429 
3430  DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3431  cjBuf, pvBuf, pmat2);
3432 
3433  pdcattr = dc->pdcattr;
3434 
3435  MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
3436  eM11 = xForm.eM11;
3437 
3438  hFont = pdcattr->hlfntNew;
3439  TextObj = RealizeFontInit(hFont);
3440 
3441  if (!TextObj)
3442  {
3444  return GDI_ERROR;
3445  }
3446  FontGDI = ObjToGDI(TextObj->Font, FONT);
3447  ft_face = FontGDI->SharedFace->Face;
3448 
3449  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3450  aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3451  orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3452 
3453  Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3455  if (!potm)
3456  {
3458  TEXTOBJ_UnlockText(TextObj);
3459  return GDI_ERROR;
3460  }
3461  Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
3462  if (!Size)
3463  {
3464  /* FIXME: last error? */
3466  TEXTOBJ_UnlockText(TextObj);
3467  return GDI_ERROR;
3468  }
3469 
3470  IntLockFreeType();
3471  TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3473 
3474  TEXTOBJ_UnlockText(TextObj);
3475 
3476  glyph_index = get_glyph_index_flagged(ft_face, wch, GGO_GLYPH_INDEX, iFormat);
3477  iFormat &= ~GGO_GLYPH_INDEX;
3478 
3479  if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3480  load_flags |= FT_LOAD_NO_BITMAP;
3481 
3482  if (iFormat & GGO_UNHINTED)
3483  {
3484  load_flags |= FT_LOAD_NO_HINTING;
3485  iFormat &= ~GGO_UNHINTED;
3486  }
3487 
3488  error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3489  if (error)
3490  {
3491  DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3493  if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3494  return GDI_ERROR;
3495  }
3497 
3498  if (aveWidth && potm)
3499  {
3500  widthRatio = (FLOAT)aveWidth * eM11 /
3502  }
3503 
3504  left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3505  right = (INT)((ft_face->glyph->metrics.horiBearingX +
3506  ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3507 
3508  adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3509  lsb = left >> 6;
3510  bbx = (right - left) >> 6;
3511 
3512  DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3513 
3514  IntLockFreeType();
3515 
3516  /* Width scaling transform */
3517  if (widthRatio != 1.0)
3518  {
3519  FT_Matrix scaleMat;
3520  scaleMat.xx = FT_FixedFromFloat(widthRatio);
3521  scaleMat.xy = 0;
3522  scaleMat.yx = 0;
3523  scaleMat.yy = FT_FixedFromFloat(1.0);
3524 
3525  FT_Matrix_Multiply(&scaleMat, &transMat);
3526  needsTransform = TRUE;
3527  }
3528 
3529  /* World transform */
3530  {
3531  FT_Matrix ftmatrix;
3532  FLOATOBJ efTemp;
3533  PMATRIX pmx = DC_pmxWorldToDevice(dc);
3534 
3535  /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3536  efTemp = pmx->efM11;
3537  FLOATOBJ_MulLong(&efTemp, 0x00010000);
3538  ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
3539 
3540  efTemp = pmx->efM12;
3541  FLOATOBJ_MulLong(&efTemp, 0x00010000);
3542  ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
3543 
3544  efTemp = pmx->efM21;
3545  FLOATOBJ_MulLong(&efTemp, 0x00010000);
3546  ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
3547 
3548  efTemp = pmx->efM22;
3549  FLOATOBJ_MulLong(&efTemp, 0x00010000);
3550  ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
3551 
3552  if (memcmp(&ftmatrix, &identityMat, sizeof(identityMat)) != 0)
3553  {
3554  FT_Matrix_Multiply(&ftmatrix, &transMat);
3555  needsTransform = TRUE;
3556  }
3557  }
3558 
3559  /* Rotation transform */
3560  if (orientation)
3561  {
3562  FT_Matrix rotationMat;
3563  FT_Vector vecAngle;
3564  DPRINT("Rotation Trans!\n");
3565  angle = FT_FixedFromFloat((float)orientation / 10.0);
3566  FT_Vector_Unit(&vecAngle, angle);
3567  rotationMat.xx = vecAngle.x;
3568  rotationMat.xy = -vecAngle.y;
3569  rotationMat.yx = -rotationMat.xy;
3570  rotationMat.yy = rotationMat.xx;
3571  FT_Matrix_Multiply(&rotationMat, &transMat);
3572  needsTransform = TRUE;
3573  }
3574 
3575  /* Extra transformation specified by caller */
3576  if (pmat2)
3577  {
3578  FT_Matrix extraMat;
3579  DPRINT("MAT2 Matrix Trans!\n");
3580  extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
3581  extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
3582  extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
3583  extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
3584  FT_Matrix_Multiply(&extraMat, &transMat);
3585  needsTransform = TRUE;
3586  }
3587 
3588  if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
3589 
3590  if (!needsTransform)
3591  {
3592  DPRINT("No Need to be Transformed!\n");
3593  top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3594  bottom = (ft_face->glyph->metrics.horiBearingY -
3595  ft_face->glyph->metrics.height) & -64;
3596  gm.gmCellIncX = adv;
3597  gm.gmCellIncY = 0;
3598  }
3599  else
3600  {
3601  INT xc, yc;
3602  FT_Vector vec;
3603  for (xc = 0; xc < 2; xc++)
3604  {
3605  for (yc = 0; yc < 2; yc++)
3606  {
3607  vec.x = (ft_face->glyph->metrics.horiBearingX +
3608  xc * ft_face->glyph->metrics.width);
3609  vec.y = ft_face->glyph->metrics.horiBearingY -
3610  yc * ft_face->glyph->metrics.height;
3611  DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
3612  FT_Vector_Transform(&vec, &transMat);
3613  if (xc == 0 && yc == 0)
3614  {
3615  left = right = vec.x;
3616  top = bottom = vec.y;
3617  }
3618  else
3619  {
3620  if (vec.x < left) left = vec.x;
3621  else if (vec.x > right) right = vec.x;
3622  if (vec.y < bottom) bottom = vec.y;
3623  else if (vec.y > top) top = vec.y;
3624  }
3625  }
3626  }
3627  left = left & -64;
3628  right = (right + 63) & -64;
3629  bottom = bottom & -64;
3630  top = (top + 63) & -64;
3631 
3632  DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3633  vec.x = ft_face->glyph->metrics.horiAdvance;
3634  vec.y = 0;
3635  FT_Vector_Transform(&vec, &transMat);
3636  gm.gmCellIncX = (vec.x+63) >> 6;
3637  gm.gmCellIncY = -((vec.y+63) >> 6);
3638  }
3639  gm.gmBlackBoxX = (right - left) >> 6;
3640  gm.gmBlackBoxY = (top - bottom) >> 6;
3641  gm.gmptGlyphOrigin.x = left >> 6;
3642  gm.gmptGlyphOrigin.y = top >> 6;
3643 
3644  DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
3645  gm.gmCellIncX, gm.gmCellIncY,
3646  gm.gmBlackBoxX, gm.gmBlackBoxY,
3648 
3650 
3651 
3652  if (iFormat == GGO_METRICS)
3653  {
3654  DPRINT("GGO_METRICS Exit!\n");
3655  *pgm = gm;
3656  return 1; /* FIXME */
3657  }
3658 
3659  if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
3660  {
3661  DPRINT1("Loaded a bitmap\n");
3662  return GDI_ERROR;
3663  }
3664 
3665  switch (iFormat)
3666  {
3667  case GGO_BITMAP:
3668  width = gm.gmBlackBoxX;
3669  height = gm.gmBlackBoxY;
3670  pitch = ((width + 31) >> 5) << 2;
3671  needed = pitch * height;
3672 
3673  if (!pvBuf || !cjBuf) break;
3674  if (!needed) return GDI_ERROR; /* empty glyph */
3675  if (needed > cjBuf)
3676  return GDI_ERROR;
3677 
3678  switch (ft_face->glyph->format)
3679  {
3681  {
3682  BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3683  INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
3684  INT h = min( height, ft_face->glyph->bitmap.rows );
3685  while (h--)
3686  {
3687  RtlCopyMemory(dst, src, w);
3688  src += ft_face->glyph->bitmap.pitch;
3689  dst += pitch;
3690  }
3691  break;
3692  }
3693 
3695  ft_bitmap.width = width;
3696  ft_bitmap.rows = height;
3697  ft_bitmap.pitch = pitch;
3698  ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
3699  ft_bitmap.buffer = pvBuf;
3700 
3701  IntLockFreeType();
3702  if (needsTransform)
3703  {
3704  FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3705  }
3706  FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3707  /* Note: FreeType will only set 'black' bits for us. */
3708  RtlZeroMemory(pvBuf, needed);
3709  FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
3711  break;
3712 
3713  default:
3714  DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3715  return GDI_ERROR;
3716  }
3717  break;
3718 
3719  case GGO_GRAY2_BITMAP:
3720  case GGO_GRAY4_BITMAP:
3721  case GGO_GRAY8_BITMAP:
3722  {
3723  unsigned int mult, row, col;
3724  BYTE *start, *ptr;
3725 
3726  width = gm.gmBlackBoxX;
3727  height = gm.gmBlackBoxY;
3728  pitch = (width + 3) / 4 * 4;
3729  needed = pitch * height;
3730 
3731  if (!pvBuf || !cjBuf) break;
3732  if (!needed) return GDI_ERROR; /* empty glyph */
3733  if (needed > cjBuf)
3734  return GDI_ERROR;
3735 
3736  switch (ft_face->glyph->format)
3737  {
3739  {
3740  BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3741  INT h = min( height, ft_face->glyph->bitmap.rows );
3742  INT x;
3743  while (h--)
3744  {
3745  for (x = 0; (UINT)x < pitch; x++)
3746  {
3747  if (x < ft_face->glyph->bitmap.width)
3748  dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3749  else
3750  dst[x] = 0;
3751  }
3752  src += ft_face->glyph->bitmap.pitch;
3753  dst += pitch;
3754  }
3755  break;
3756  }
3758  {
3759  ft_bitmap.width = width;
3760  ft_bitmap.rows = height;
3761  ft_bitmap.pitch = pitch;
3762  ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3763  ft_bitmap.buffer = pvBuf;
3764 
3765  IntLockFreeType();
3766  if (needsTransform)
3767  {
3768  FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3769  }
3770  FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3771  RtlZeroMemory(ft_bitmap.buffer, cjBuf);
3772  FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
3774 
3775  if (iFormat == GGO_GRAY2_BITMAP)
3776  mult = 4;
3777  else if (iFormat == GGO_GRAY4_BITMAP)
3778  mult = 16;
3779  else if (iFormat == GGO_GRAY8_BITMAP)
3780  mult = 64;
3781  else
3782  {
3783  return GDI_ERROR;
3784  }
3785 
3786  start = pvBuf;
3787  for (row = 0; row < height; row++)
3788  {
3789  ptr = start;
3790  for (col = 0; col < width; col++, ptr++)
3791  {
3792  *ptr = (((int)*ptr) * mult + 128) / 256;
3793  }
3794  start += pitch;
3795  }
3796 
3797  break;
3798  }
3799  default:
3800  DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3801  return GDI_ERROR;
3802  }
3803  }
3804 
3805  case GGO_NATIVE:
3806  {
3807  FT_Outline *outline = &ft_face->glyph->outline;
3808 
3809  if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
3810 
3811  IntLockFreeType();
3812  if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
3813 
3814  needed = get_native_glyph_outline(outline, cjBuf, NULL);
3815 
3816  if (!pvBuf || !cjBuf)
3817  {
3819  break;
3820  }
3821  if (needed > cjBuf)
3822  {
3824  return GDI_ERROR;
3825  }
3826  get_native_glyph_outline(outline, cjBuf, pvBuf);
3828  break;
3829  }
3830  case GGO_BEZIER:
3831  {
3832  FT_Outline *outline = &ft_face->glyph->outline;
3833  if (cjBuf == 0) pvBuf = NULL;
3834 
3835  if (needsTransform && pvBuf)
3836  {
3837  IntLockFreeType();
3838  FT_Outline_Transform(outline, &transMat);
3840  }
3841  needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
3842 
3843  if (!pvBuf || !cjBuf)
3844  break;
3845  if (needed > cjBuf)
3846  return GDI_ERROR;
3847 
3848  get_bezier_glyph_outline(outline, cjBuf, pvBuf);
3849  break;
3850  }
3851 
3852  default:
3853  DPRINT1("Unsupported format %u\n", iFormat);
3854  return GDI_ERROR;
3855  }
3856 
3857  DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
3858  *pgm = gm;
3859  return needed;
3860 }
3861 
3862 BOOL
3863 FASTCALL
3865  PTEXTOBJ TextObj,
3866  LPCWSTR String,
3867  INT Count,
3868  ULONG MaxExtent,
3869  LPINT Fit,
3870  LPINT Dx,
3871  LPSIZE Size,
3872  FLONG fl)
3873 {
3874  PFONTGDI FontGDI;
3875  FT_Face face;
3876  FT_GlyphSlot glyph;
3877  FT_BitmapGlyph realglyph;
3878  INT error, glyph_index, i, previous;
3879  ULONGLONG TotalWidth = 0;
3880  BOOL use_kerning;
3881  FT_Render_Mode RenderMode;
3882  BOOLEAN Render;
3883  PMATRIX pmxWorldToDevice;
3884  LOGFONTW *plf;
3885  BOOL EmuBold, EmuItalic;
3886  LONG ascender, descender;
3887 
3888  FontGDI = ObjToGDI(TextObj->Font, FONT);
3889 
3890  face = FontGDI->SharedFace->Face;
3891  if (NULL != Fit)
3892  {
3893  *Fit = 0;
3894  }
3895 
3896  IntLockFreeType();
3897 
3898  TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3899 
3900  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3901  EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
3902  EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
3903 
3904  Render = IntIsFontRenderingEnabled();
3905  if (Render)
3906  RenderMode = IntGetFontRenderMode(plf);
3907  else
3908  RenderMode = FT_RENDER_MODE_MONO;
3909 
3910  /* Get the DC's world-to-device transformation matrix */
3911  pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3912  FtSetCoordinateTransform(face, pmxWorldToDevice);
3913 
3914  use_kerning = FT_HAS_KERNING(face);
3915  previous = 0;
3916 
3917  for (i = 0; i < Count; i++)
3918  {
3919  glyph_index = get_glyph_index_flagged(face, *String, GTEF_INDICES, fl);
3920 
3921  if (EmuBold || EmuItalic)
3922  realglyph = NULL;
3923  else
3924  realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
3925  RenderMode, pmxWorldToDevice);
3926 
3927  if (EmuBold || EmuItalic || !realglyph)
3928  {
3929  error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3930  if (error)
3931  {
3932  DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
3933  break;
3934  }
3935 
3936  glyph = face->glyph;
3937  if (EmuBold || EmuItalic)
3938  {
3939  if (EmuBold)
3940  FT_GlyphSlot_Embolden(glyph);
3941  if (EmuItalic)
3942  FT_GlyphSlot_Oblique(glyph);
3943  realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
3944  }
3945  else
3946  {
3947  realglyph = ftGdiGlyphCacheSet(face,
3948  glyph_index,
3949  plf->lfHeight,
3950  pmxWorldToDevice,
3951  glyph,
3952  RenderMode);
3953  }
3954 
3955  if (!realglyph)
3956  {
3957  DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3958  break;
3959  }
3960  }
3961 
3962  /* Retrieve kerning distance */
3963  if (use_kerning && previous && glyph_index)
3964  {
3965  FT_Vector delta;
3966  FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3967  TotalWidth += delta.x;
3968  }
3969 
3970  TotalWidth += realglyph->root.advance.x >> 10;
3971 
3972  if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
3973  {
3974  *Fit = i + 1;
3975  }
3976  if (NULL != Dx)
3977  {
3978  Dx[i] = (TotalWidth + 32) >> 6;
3979  }
3980 
3981  if (EmuBold || EmuItalic)
3982  {
3983  FT_Done_Glyph((FT_Glyph)realglyph);
3984  realglyph = NULL;
3985  }
3986 
3987  previous = glyph_index;
3988  String++;
3989  }
3990  ASSERT(FontGDI->Magic == FONTGDI_MAGIC);
3991  ascender = FontGDI->tmAscent; /* Units above baseline */
3992  descender = FontGDI->tmDescent; /* Units below baseline */
3994 
3995  Size->cx = (TotalWidth + 32) >> 6;
3996  Size->cy = ascender + descender;
3997 
3998  return TRUE;
3999 }
4000 
4001 
4002 INT
4003 FASTCALL
4005  PDC Dc,
4006  LPFONTSIGNATURE lpSig,
4007  DWORD dwFlags)
4008 {
4009  PDC_ATTR pdcattr;
4010  UINT Ret = DEFAULT_CHARSET;
4011  INT i;
4012  HFONT hFont;
4013  PTEXTOBJ TextObj;
4014  PFONTGDI FontGdi;
4015  FONTSIGNATURE fs;
4016  TT_OS2 *pOS2;
4017  FT_Face Face;
4018  CHARSETINFO csi;
4019  DWORD cp, fs0;
4020  USHORT usACP, usOEM;
4021 
4022  pdcattr = Dc->pdcattr;
4023  hFont = pdcattr->hlfntNew;
4024  TextObj = RealizeFontInit(hFont);
4025 
4026  if (!TextObj)
4027  {
4029  return Ret;
4030  }
4031  FontGdi = ObjToGDI(TextObj->Font, FONT);
4032  Face = FontGdi->SharedFace->Face;
4033  TEXTOBJ_UnlockText(TextObj);
4034 
4035  IntLockFreeType();
4036  pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4038  memset(&fs, 0, sizeof(FONTSIGNATURE));
4039  if (NULL != pOS2)
4040  {
4041  fs.fsCsb[0] = pOS2->ulCodePageRange1;
4042  fs.fsCsb[1] = pOS2->ulCodePageRange2;
4043  fs.fsUsb[0] = pOS2->ulUnicodeRange1;
4044  fs.fsUsb[1] = pOS2->ulUnicodeRange2;
4045  fs.fsUsb[2] = pOS2->ulUnicodeRange3;
4046  fs.fsUsb[3] = pOS2->ulUnicodeRange4;
4047  if (pOS2->version == 0)
4048  {
4049  FT_UInt dummy;
4050 
4051  if (FT_Get_First_Char( Face, &dummy ) < 0x100)
4052  fs.fsCsb[0] |= FS_LATIN1;
4053  else
4054  fs.fsCsb[0] |= FS_SYMBOL;
4055  }
4056  }
4057  DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
4058  if (fs.fsCsb[0] == 0)
4059  { /* Let's see if we can find any interesting cmaps */
4060  for (i = 0; i < Face->num_charmaps; i++)
4061  {
4062  switch (Face->charmaps[i]->encoding)
4063  {
4064  case FT_ENCODING_UNICODE:
4065  case FT_ENCODING_APPLE_ROMAN:
4066  fs.fsCsb[0] |= FS_LATIN1;
4067  break;
4068  case FT_ENCODING_MS_SYMBOL:
4069  fs.fsCsb[0] |= FS_SYMBOL;
4070  break;
4071  default:
4072  break;
4073  }
4074  }
4075  }
4076  if (lpSig)
4077  {
4078  RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
4079  }
4080 
4081  RtlGetDefaultCodePage(&usACP, &usOEM);
4082  cp = usACP;
4083 
4084  if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
4085  if (csi.fs.fsCsb[0] & fs.fsCsb[0])
4086  {
4087  DPRINT("Hit 1\n");
4088  Ret = csi.ciCharset;
4089  goto Exit;
4090  }
4091 
4092  for (i = 0; i < MAXTCIINDEX; i++)
4093  {
4094  fs0 = 1L << i;
4095  if (fs.fsCsb[0] & fs0)
4096  {
4097  if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
4098  {
4099  // *cp = csi.ciACP;
4100  DPRINT("Hit 2\n");
4101  Ret = csi.ciCharset;
4102  goto Exit;
4103  }
4104  else
4105  DPRINT1("TCI failing on %x\n", fs0);
4106  }
4107  }
4108 Exit:
4109  DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
4110  return (MAKELONG(csi.ciACP, csi.ciCharset));
4111 }
4112 
4113 
4114 DWORD
4115 FASTCALL
4117 {
4118  DWORD size = 0;
4119  DWORD num_ranges = 0;
4120  FT_Face face = Font->SharedFace->Face;
4121 
4122  if (face->charmap->encoding == FT_ENCODING_UNICODE)
4123  {
4124  FT_UInt glyph_code = 0;
4125  FT_ULong char_code, char_code_prev;
4126 
4127  char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
4128 
4129  DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4130  face->num_glyphs, glyph_code, char_code);
4131 
4132  if (!glyph_code) return 0;
4133 
4134  if (glyphset)
4135  {
4136  glyphset->ranges[0].wcLow = (USHORT)char_code;
4137  glyphset->ranges[0].cGlyphs = 0;
4138  glyphset->cGlyphsSupported = 0;
4139  }
4140 
4141  num_ranges = 1;
4142  while (glyph_code)
4143  {
4144  if (char_code < char_code_prev)
4145  {
4146  DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
4147  return 0;
4148  }
4149  if (char_code - char_code_prev > 1)
4150  {
4151  num_ranges++;
4152  if (glyphset)
4153  {
4154  glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4155  glyphset->ranges[num_ranges - 1].cGlyphs = 1;
4156  glyphset->cGlyphsSupported++;
4157  }
4158  }
4159  else if (glyphset)
4160  {
4161  glyphset->ranges[num_ranges - 1].cGlyphs++;
4162  glyphset->cGlyphsSupported++;
4163  }
4164  char_code_prev = char_code;
4165  char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
4166  }
4167  }
4168  else
4169  DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
4170 
4171  size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4172  if (glyphset)
4173  {
4174  glyphset->cbThis = size;
4175  glyphset->cRanges = num_ranges;
4176  glyphset->flAccel = 0;
4177  }
4178  return size;
4179 }
4180 
4181 
4182 BOOL
4183 FASTCALL
4185  HDC hDC,
4186  PTMW_INTERNAL ptmwi)
4187 {
4188  PDC dc;
4189  PDC_ATTR pdcattr;
4190  PTEXTOBJ TextObj;
4191  PFONTGDI FontGDI;
4192  FT_Face Face;
4193  TT_OS2 *pOS2;
4194  TT_HoriHeader *pHori;
4195  FT_WinFNT_HeaderRec Win;
4196  ULONG Error;
4198  LOGFONTW *plf;
4199 
4200  if (!ptmwi)
4201  {
4203  return FALSE;
4204  }
4205 
4206  if (!(dc = DC_LockDc(hDC)))
4207  {
4209  return FALSE;
4210  }
4211  pdcattr = dc->pdcattr;
4212  TextObj = RealizeFontInit(pdcattr->hlfntNew);
4213  if (NULL != TextObj)
4214  {
4215  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4216  FontGDI = ObjToGDI(TextObj->Font, FONT);
4217 
4218  Face = FontGDI->SharedFace->Face;
4219 
4220  IntLockFreeType();
4221  Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
4224 
4225  if (0 != Error)
4226  {
4227  DPRINT1("Error in setting pixel sizes: %u\n", Error);
4228  Status = STATUS_UNSUCCESSFUL;
4229  }
4230  else
4231  {
4232  FT_Face Face = FontGDI->SharedFace->Face;
4233  Status = STATUS_SUCCESS;
4234 
4235  IntLockFreeType();
4236  pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4237  if (NULL == pOS2)
4238  {
4239  DPRINT1("Can't find OS/2 table - not TT font?\n");
4240  Status = STATUS_INTERNAL_ERROR;
4241  }
4242 
4243  pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
4244  if (NULL == pHori)
4245  {
4246  DPRINT1("Can't find HHEA table - not TT font?\n");
4247  Status = STATUS_INTERNAL_ERROR;
4248  }
4249 
4250  Error = FT_Get_WinFNT_Header(Face, &Win);
4251 
4253 
4254  if (NT_SUCCESS(Status))
4255  {
4256  FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
4257 
4258  /* FIXME: Fill Diff member */
4259  RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
4260  }
4261  }
4262  TEXTOBJ_UnlockText(TextObj);
4263  }
4264  else
4265  {
4266  Status = STATUS_INVALID_HANDLE;
4267  }
4268  DC_UnlockDc(dc);
4269 
4270  if (!NT_SUCCESS(Status))
4271  {
4272  SetLastNtError(Status);
4273  return FALSE;
4274  }
4275  return TRUE;
4276 }
4277 
4278 DWORD
4279 FASTCALL
4281  PFONTGDI FontGdi,
4282  DWORD Table,
4283  DWORD Offset,
4284  PVOID Buffer,
4285  DWORD Size)
4286 {
4288  FT_Face Face = FontGdi->SharedFace->Face;
4289 
4290  IntLockFreeType();
4291 
4292  if (FT_IS_SFNT(Face))
4293  {
4294  if (Table)
4295  Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
4296  (Table << 8 & 0xFF0000);
4297 
4298  if (!Buffer) Size = 0;
4299 
4300  if (Buffer && Size)
4301  {
4302  FT_Error Error;
4303  FT_ULong Needed = 0;
4304 
4305  Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
4306 
4307  if ( !Error && Needed < Size) Size = Needed;
4308  }
4309  if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
4310  Result = Size;
4311  }
4312 
4314 
4315  return Result;
4316 }
4317 
4318 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
4319 static UINT
4320 GetFontPenalty(const LOGFONTW * LogFont,
4321  const OUTLINETEXTMETRICW * Otm,
4322  const char * style_name)
4323 {
4324  ULONG Penalty = 0;
4325  BYTE Byte;
4326  LONG Long;
4327  BOOL fNeedScaling = FALSE;
4328  const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
4329  const TEXTMETRICW * TM = &Otm->otmTextMetrics;
4330  WCHAR* ActualNameW;
4331 
4332  ASSERT(Otm);
4333  ASSERT(LogFont);
4334 
4335  /* FIXME: IntSizeSynth Penalty 20 */
4336  /* FIXME: SmallPenalty Penalty 1 */
4337  /* FIXME: FaceNameSubst Penalty 500 */
4338 
4339  Byte = LogFont->lfCharSet;
4340  if (Byte == DEFAULT_CHARSET)
4341  {
4342  if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0)
4343  {
4344  if (Byte == ANSI_CHARSET)
4345  {
4346  DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
4347  }
4348  /* We assume SYMBOL_CHARSET for "Marlett" font */
4349  Byte = SYMBOL_CHARSET;
4350  }
4351  }
4352 
4353  if (Byte != TM->tmCharSet)
4354  {
4355  if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
4356  {
4357  /* CharSet Penalty 65000 */
4358  /* Requested charset does not match the candidate's. */
4359  Penalty += 65000;
4360  }
4361  else
4362  {
4363  if (UserCharSet != TM->tmCharSet)
4364  {
4365  /* UNDOCUMENTED */
4366  Penalty += 100;
4367  if (ANSI_CHARSET != TM->tmCharSet)
4368  {
4369  /* UNDOCUMENTED */
4370  Penalty += 100;
4371  }
4372  }
4373  }
4374  }
4375 
4376  Byte = LogFont->lfOutPrecision;
4377  if (Byte == OUT_DEFAULT_PRECIS)
4378  Byte = OUT_OUTLINE_PRECIS; /* Is it OK? */
4379  switch (Byte)
4380  {
4381  case OUT_DEVICE_PRECIS:
4382  if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
4384  {
4385  /* OutputPrecision Penalty 19000 */
4386  /* Requested OUT_STROKE_PRECIS, but the device can't do it
4387  or the candidate is not a vector font. */
4388  Penalty += 19000;
4389  }
4390  break;
4391  default:
4393  {
4394  /* OutputPrecision Penalty 19000 */
4395  /* Or OUT_STROKE_PRECIS not requested, and the candidate
4396  is a vector font that requires GDI support. */
4397  Penalty += 19000;
4398  }
4399  break;
4400  }
4401 
4402  Byte = (LogFont->lfPitchAndFamily & 0x0F);
4403  if (Byte == DEFAULT_PITCH)
4404  Byte = VARIABLE_PITCH;
4405  if (Byte == FIXED_PITCH)
4406  {
4408  {
4409  /* FixedPitch Penalty 15000 */
4410  /* Requested a fixed pitch font, but the candidate is a
4411  variable pitch font. */
4412  Penalty += 15000;
4413  }
4414  }
4415  if (Byte == VARIABLE_PITCH)
4416  {
4418  {
4419  /* PitchVariable Penalty 350 */
4420  /* Requested a variable pitch font, but the candidate is not a
4421  variable pitch font. */
4422  Penalty += 350;
4423  }
4424  }
4425 
4426  Byte = (LogFont->lfPitchAndFamily & 0x0F);
4427  if (Byte == DEFAULT_PITCH)
4428  {
4430  {
4431  /* DefaultPitchFixed Penalty 1 */
4432  /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
4433  Penalty += 1;
4434  }
4435  }
4436 
4437  ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
4438 
4439  if (LogFont->lfFaceName[0])
4440  {
4441  BOOL Found = FALSE;
4442 
4443  /* localized family name */
4444  if (!Found)
4445  {
4446  Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4447  }
4448  /* localized full name */
4449  if (!Found)
4450  {
4451  ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
4452  Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4453  }
4454  if (!Found)
4455  {
4456  /* FaceName Penalty 10000 */
4457  /* Requested a face name, but the candidate's face name
4458  does not match. */
4459  Penalty += 10000;
4460  }
4461  }
4462 
4463  Byte = (LogFont->lfPitchAndFamily & 0xF0);
4464  if (Byte != FF_DONTCARE)
4465  {
4466  if (Byte != (TM->tmPitchAndFamily & 0xF0))
4467  {
4468  /* Family Penalty 9000 */
4469  /* Requested a family, but the candidate's family is different. */
4470  Penalty += 9000;
4471  }
4472  if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
4473  {
4474  /* FamilyUnknown Penalty 8000 */
4475  /* Requested a family, but the candidate has no family. */
4476  Penalty += 8000;
4477  }
4478  }
4479 
4480  /* Is the candidate a non-vector font? */
4481  if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4482  {
4483  /* Is lfHeight specified? */
4484  if (LogFont->lfHeight != 0)
4485  {
4486  if (labs(LogFont->lfHeight) < TM->tmHeight)
4487  {
4488  /* HeightBigger Penalty 600 */
4489  /* The candidate is a nonvector font and is bigger than the
4490  requested height. */
4491  Penalty += 600;
4492  /* HeightBiggerDifference Penalty 150 */
4493  /* The candidate is a raster font and is larger than the
4494  requested height. Penalty * height difference */
4495  Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4496 
4497  fNeedScaling = TRUE;
4498  }
4499  if (TM->tmHeight < labs(LogFont->lfHeight))
4500  {
4501  /* HeightSmaller Penalty 150 */
4502  /* The candidate is a raster font and is smaller than the
4503  requested height. Penalty * height difference */
4504  Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4505 
4506  fNeedScaling = TRUE;
4507  }
4508  }
4509  }
4510 
4511  switch (LogFont->lfPitchAndFamily & 0xF0)
4512  {
4513  case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4514  switch (TM->tmPitchAndFamily & 0xF0)
4515  {
4516  case FF_DECORATIVE: case FF_SCRIPT:
4517  /* FamilyUnlikely Penalty 50 */
4518  /* Requested a roman/modern/swiss family, but the
4519  candidate is decorative/script. */
4520  Penalty += 50;
4521  break;
4522  default:
4523  break;
4524  }
4525  break;
4526  case FF_DECORATIVE: case FF_SCRIPT:
4527  switch (TM->tmPitchAndFamily & 0xF0)
4528  {
4529  case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4530  /* FamilyUnlikely Penalty 50 */
4531  /* Or requested decorative/script, and the candidate is
4532  roman/modern/swiss. */
4533  Penalty += 50;
4534  break;
4535  default:
4536  break;
4537  }
4538  default:
4539  break;
4540  }
4541 
4542  if (LogFont->lfWidth != 0)
4543  {
4544  if (LogFont->lfWidth != TM->tmAveCharWidth)
4545  {
4546  /* Width Penalty 50 */
4547  /* Requested a nonzero width, but the candidate's width
4548  doesn't match. Penalty * width difference */
4549  Penalty += 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth);
4550 
4551  if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4552  fNeedScaling = TRUE;
4553  }
4554  }
4555 
4556  if (fNeedScaling)
4557  {
4558  /* SizeSynth Penalty 50 */
4559  /* The candidate is a raster font that needs scaling by GDI. */
4560  Penalty += 50;
4561  }
4562 
4563  if (!!LogFont->lfItalic != !!TM->tmItalic)
4564  {
4565  if (!LogFont->lfItalic && ItalicFromStyle(style_name))
4566  {
4567  /* Italic Penalty 4 */
4568  /* Requested font and candidate font do not agree on italic status,
4569  and the desired result cannot be simulated. */
4570  /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
4571  Penalty += 40;
4572  }
4573  else if (LogFont->lfItalic && !ItalicFromStyle(style_name))
4574  {
4575  /* ItalicSim Penalty 1 */
4576  /* Requested italic font but the candidate is not italic,
4577  although italics can be simulated. */
4578  Penalty += 1;
4579  }
4580  }
4581 
4582  if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
4583  {
4584  if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
4585  {
4586  /* NotTrueType Penalty 4 */
4587  /* Requested OUT_TT_PRECIS, but the candidate is not a
4588  TrueType font. */
4589  Penalty += 4;
4590  }
4591  }
4592 
4593  Long = LogFont->lfWeight;
4594  if (LogFont->lfWeight == FW_DONTCARE)
4595  Long = FW_NORMAL;
4596  if (Long != TM->tmWeight)
4597  {
4598  /* Weight Penalty 3 */
4599  /* The candidate's weight does not match the requested weight.
4600  Penalty * (weight difference/10) */
4601  Penalty += 3 * (labs(Long - TM->tmWeight) / 10);
4602  }
4603 
4604  if (!LogFont->lfUnderline && TM->tmUnderlined)
4605  {
4606  /* Underline Penalty 3 */
4607  /* Requested font has no underline, but the candidate is
4608  underlined. */
4609  Penalty += 3;
4610  }
4611 
4612  if (!LogFont->lfStrikeOut && TM->tmStruckOut)
4613  {
4614  /* StrikeOut Penalty 3 */
4615  /* Requested font has no strike-out, but the candidate is
4616  struck out. */
4617  Penalty += 3;
4618  }
4619 
4620  /* Is the candidate a non-vector font? */
4621  if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4622  {
4623  if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
4624  {
4625  /* VectorHeightSmaller Penalty 2 */
4626  /* Candidate is a vector font that is smaller than the
4627  requested height. Penalty * height difference */
4628  Penalty += 2 * labs(TM->tmHeight - LogFont->lfHeight);
4629  }
4630  if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
4631  {
4632  /* VectorHeightBigger Penalty 1 */
4633  /* Candidate is a vector font that is bigger than the
4634  requested height. Penalty * height difference */
4635  Penalty += 1 * labs(TM->tmHeight - LogFont->lfHeight);
4636  }
4637  }
4638 
4639  if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
4640  {
4641  /* DeviceFavor Penalty 2 */
4642  /* Extra penalty for all nondevice fonts. */
4643  Penalty += 2;
4644  }
4645 
4646  if (TM->tmAveCharWidth >= 5 && TM->tmHeight >= 5)
4647  {
4648  if (TM->tmAveCharWidth / TM->tmHeight >= 3)
4649  {
4650  /* Aspect Penalty 30 */
4651  /* The aspect rate is >= 3. It seems like a bad font. */
4652  Penalty += ((TM->tmAveCharWidth / TM->tmHeight) - 2) * 30;
4653  }
4654  else if (TM->tmHeight / TM->tmAveCharWidth >= 3)
4655  {
4656  /* Aspect Penalty 30 */
4657  /* The aspect rate is >= 3. It seems like a bad font. */
4658  Penalty += ((TM->tmHeight / TM->tmAveCharWidth) - 2) * 30;
4659  }
4660  }
4661 
4662  if (Penalty < 200)
4663  {
4664  DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
4665  "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
4666  "tmCharSet:%d, tmWeight:%ld\n",
4667  Penalty, LogFont->lfFaceName, ActualNameW,
4668  LogFont->lfCharSet, LogFont->lfWeight,
4669  TM->tmCharSet, TM->tmWeight);
4670  }
4671 
4672  return Penalty; /* success */
4673 }
4674 
4675 static __inline VOID
4676 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
4677  const LOGFONTW *LogFont,
4678  const PLIST_ENTRY Head)
4679 {
4680  ULONG Penalty;
4682  PFONT_ENTRY CurrentEntry;
4683  FONTGDI *FontGDI;
4684  OUTLINETEXTMETRICW *Otm = NULL;
4685  UINT OtmSize, OldOtmSize = 0;
4686  FT_Face Face;
4687 
4688  ASSERT(FontObj);
4689  ASSERT(MatchPenalty);
4690  ASSERT(LogFont);
4691  ASSERT(Head);
4692 
4693  /* Start with a pretty big buffer */
4694  OldOtmSize = 0x200;
4695  Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
4696 
4697  /* get the FontObj of lowest penalty */
4698  for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
4699  {
4700  CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
4701 
4702  FontGDI = CurrentEntry->Font;
4703  ASSERT(FontGDI);
4704  Face = FontGDI->SharedFace->Face;
4705 
4706  /* get text metrics */
4707  OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4708  if (OtmSize > OldOtmSize)
4709  {
4710  if (Otm)
4712  Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
4713  }
4714 
4715  /* update FontObj if lowest penalty */
4716  if (Otm)
4717  {
4718  IntLockFreeType();
4719  IntRequestFontSize(NULL, FontGDI, LogFont->lfWidth, LogFont->lfHeight);
4721 
4722  OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
4723  if (!OtmSize)
4724  continue;
4725 
4726  OldOtmSize = OtmSize;
4727 
4728  Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
4729  if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
4730  {
4731  *FontObj = GDIToObj(FontGDI, FONT);
4732  *MatchPenalty = Penalty;
4733  }
4734  }
4735  }
4736 
4737  if (Otm)
4739 }
4740 
4741 static
4742 VOID
4743 FASTCALL
4745 {
4746  PS_FontInfoRec psfInfo;
4747  FT_ULong tmp_size = 0;
4748  FT_Face Face = Font->SharedFace->Face;
4749 
4750  if (FT_HAS_MULTIPLE_MASTERS(Face))
4752  if (FT_HAS_VERTICAL(Face))
4753  Font->FontObj.flFontType |= FO_VERT_FACE;
4754  if (!FT_IS_SCALABLE(Face))
4756  if (FT_IS_SFNT(Face))
4757  {
4759  if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
4760  Font->FontObj.flFontType |= FO_POSTSCRIPT;
4761  }
4762  if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
4763  {
4764  Font->FontObj.flFontType |= FO_POSTSCRIPT;
4765  }
4766  /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
4767  if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
4768  {
4770  }
4771 }
4772 
4773 static BOOL
4774 MatchFontName(PSHARED_FACE SharedFace, LPCWSTR lfFaceName, FT_UShort NameID, FT_UShort LangID)
4775 {
4776  NTSTATUS Status;
4777  UNICODE_STRING Name1, Name2;
4778 
4779  if (lfFaceName[0] == UNICODE_NULL)
4780  return FALSE;
4781 
4782  RtlInitUnicodeString(&Name1, lfFaceName);
4783 
4784  RtlInitUnicodeString(&Name2, NULL);
4785  Status = IntGetFontLocalizedName(&Name2, SharedFace, NameID, LangID);
4786 
4787  if (NT_SUCCESS(Status))
4788  {
4789  if (RtlCompareUnicodeString(&Name1, &Name2, TRUE) == 0)
4790  {
4791  RtlFreeUnicodeString(&Name2);
4792  return TRUE;
4793  }
4794 
4795  RtlFreeUnicodeString(&Name2);
4796  }
4797 
4798  return FALSE;
4799 }
4800 
4801 static BOOL
4802 MatchFontNames(PSHARED_FACE SharedFace, LPCWSTR lfFaceName)
4803 {
4804  if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, LANG_ENGLISH) ||
4805  MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, LANG_ENGLISH))
4806  {
4807  return TRUE;
4808  }
4810  {
4811  if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, gusLanguageID) ||
4812  MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, gusLanguageID))
4813  {
4814  return TRUE;
4815  }
4816  }
4817  return FALSE;
4818 }
4819 
4820 NTSTATUS
4821 FASTCALL
4822 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
4823 {
4825  PTEXTOBJ TextObj;
4826  PPROCESSINFO Win32Process;
4827  ULONG MatchPenalty;
4828  LOGFONTW *pLogFont;
4829  LOGFONTW SubstitutedLogFont;
4830  FT_Face Face;
4831 
4832  if (!pTextObj)
4833  {
4834  TextObj = TEXTOBJ_LockText(FontHandle);
4835  if (NULL == TextObj)
4836  {
4837  return STATUS_INVALID_HANDLE;
4838  }
4839 
4840  if (TextObj->fl & TEXTOBJECT_INIT)
4841  {
4842  TEXTOBJ_UnlockText(TextObj);
4843  return STATUS_SUCCESS;
4844  }
4845  }
4846  else
4847  {
4848  TextObj = pTextObj;
4849  }
4850 
4851  pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4852 
4853  /* substitute */
4854  SubstitutedLogFont = *pLogFont;
4855  DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
4856  SubstituteFontRecurse(&SubstitutedLogFont);
4857  DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
4858 
4859  MatchPenalty = 0xFFFFFFFF;
4860  TextObj->Font = NULL;
4861 
4862  Win32Process = PsGetCurrentProcessWin32Process();
4863 
4864  /* Search private fonts */
4865  IntLockProcessPrivateFonts(Win32Process);
4866  FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4867  &Win32Process->PrivateFontListHead);
4868  IntUnLockProcessPrivateFonts(Win32Process);
4869 
4870  /* Search system fonts */
4872  FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4873  &g_FontListHead);
4875 
4876  if (NULL == TextObj->Font)
4877  {
4878  DPRINT1("Request font %S not found, no fonts loaded at all\n",
4879  pLogFont->lfFaceName);
4880  Status = STATUS_NOT_FOUND;
4881  }
4882  else
4883  {
4885  PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
4886  PSHARED_FACE SharedFace = FontGdi->SharedFace;
4887 
4888  IntLockFreeType();
4889  IntRequestFontSize(NULL, FontGdi, pLogFont->lfWidth, pLogFont->lfHeight);
4891 
4892  TextObj->TextFace[0] = UNICODE_NULL;
4893  if (MatchFontNames(SharedFace, SubstitutedLogFont.lfFaceName))
4894  {
4895  RtlStringCchCopyW(TextObj->TextFace, _countof(TextObj->TextFace), pLogFont->lfFaceName);
4896  }
4897  else
4898  {
4899  RtlInitUnicodeString(&Name, NULL);
4900  Status = IntGetFontLocalizedName(&Name, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
4901  if (NT_SUCCESS(Status))
4902  {
4903  /* truncated copy */
4904  Name.Length = (USHORT)min(Name.Length, (LF_FACESIZE - 1) * sizeof(WCHAR));
4905  RtlStringCbCopyNW(TextObj->TextFace, Name.Length + sizeof(WCHAR), Name.Buffer, Name.Length);
4906 
4907  RtlFreeUnicodeString(&Name);
4908  }
4909  }
4910 
4911  // Need hdev, when freetype is loaded need to create DEVOBJ for
4912  // Consumer and Producer.
4913  TextObj->Font->iUniq = 1; // Now it can be cached.
4914  IntFontType(FontGdi);
4915  FontGdi->flType = TextObj->Font->flFontType;
4916  FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
4917  FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
4918  FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
4919  if (pLogFont->lfWeight != FW_DONTCARE)
4920  FontGdi->RequestWeight = pLogFont->lfWeight;
4921  else
4922  FontGdi->RequestWeight = FW_NORMAL;
4923 
4924  Face = FontGdi->SharedFace->Face;
4925 
4926  //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name);
4927 
4928  if (!FontGdi->OriginalItalic)
4929  FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name);
4930 
4931  TextObj->fl |= TEXTOBJECT_INIT;
4932  Status = STATUS_SUCCESS;
4933  }
4934 
4935  if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
4936 
4937  ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
4938 
4939  return Status;
4940 }
4941 
4942 
4943 static
4944 BOOL
4945 FASTCALL
4947  POBJECT_NAME_INFORMATION NameInfo,
4948  ULONG Size,
4950 {
4951  NTSTATUS Status;
4953  HANDLE hFile;
4955  ULONG Desired;
4956 
4957  InitializeObjectAttributes(&ObjectAttributes,
4958  FileName,
4960  NULL,
4961  NULL);
4962 
4963  Status = ZwOpenFile(
4964  &hFile,
4965  0, // FILE_READ_ATTRIBUTES,
4966  &ObjectAttributes,
4967  &IoStatusBlock,
4969  0);
4970 
4971  if (!NT_SUCCESS(Status))
4972  {
4973  DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
4974  return FALSE;
4975  }
4976 
4977  Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
4978  ZwClose(hFile);
4979  if (!NT_SUCCESS(Status))
4980  {
4981  DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
4982  return FALSE;
4983  }
4984 
4985  return TRUE;
4986 }
4987 
4988 static BOOL
4989 EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2)
4990 {
4991  const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
4992  const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
4993  const LOGFONTW *plf1 = &pLog1->elfLogFont;
4994  const LOGFONTW *plf2 = &pLog2->elfLogFont;
4995 
4996  if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0)
4997  {
4998  return FALSE;
4999  }
5000 
5001  if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0)
5002  {
5003  return FALSE;
5004  }
5005 
5006  return TRUE;
5007 }
5008 
5009 static VOID
5011 {
5012  wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
5013  if (FamInfo->EnumLogFontEx.elfStyle[0] &&
5014  _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
5015  {