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