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