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