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