ReactOS  0.4.14-dev-52-g6116262
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 BYTE
1047 ItalicFromStyle(const char *style_name)
1048 {
1049  if (style_name == NULL || style_name[0] == 0)
1050  return FALSE;
1051  if (strstr(style_name, "Italic") != NULL)
1052  return TRUE;
1053  if (strstr(style_name, "Oblique") != NULL)
1054  return TRUE;
1055  return FALSE;
1056 }
1057 
1058 static LONG
1059 WeightFromStyle(const char *style_name)
1060 {
1061  if (style_name == NULL || style_name[0] == 0)
1062  return FW_NORMAL;
1063  if (strstr(style_name, "Regular") != NULL)
1064  return FW_REGULAR;
1065  if (strstr(style_name, "Normal") != NULL)
1066  return FW_NORMAL;
1067  if (strstr(style_name, "SemiBold") != NULL)
1068  return FW_SEMIBOLD;
1069  if (strstr(style_name, "UltraBold") != NULL)
1070  return FW_ULTRABOLD;
1071  if (strstr(style_name, "DemiBold") != NULL)
1072  return FW_DEMIBOLD;
1073  if (strstr(style_name, "ExtraBold") != NULL)
1074  return FW_EXTRABOLD;
1075  if (strstr(style_name, "Bold") != NULL)
1076  return FW_BOLD;
1077  if (strstr(style_name, "UltraLight") != NULL)
1078  return FW_ULTRALIGHT;
1079  if (strstr(style_name, "ExtraLight") != NULL)
1080  return FW_EXTRALIGHT;
1081  if (strstr(style_name, "Light") != NULL)
1082  return FW_LIGHT;
1083  if (strstr(style_name, "Hairline") != NULL)
1084  return 50;
1085  if (strstr(style_name, "Book") != NULL)
1086  return 350;
1087  if (strstr(style_name, "ExtraBlack") != NULL)
1088  return 950;
1089  if (strstr(style_name, "UltraBlack") != NULL)
1090  return 1000;
1091  if (strstr(style_name, "Black") != NULL)
1092  return FW_BLACK;
1093  if (strstr(style_name, "Medium") != NULL)
1094  return FW_MEDIUM;
1095  if (strstr(style_name, "Thin") != NULL)
1096  return FW_THIN;
1097  if (strstr(style_name, "Heavy") != NULL)
1098  return FW_HEAVY;
1099  return FW_NORMAL;
1100 }
1101 
1102 static FT_Error
1103 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight);
1104 
1105 /* NOTE: If nIndex < 0 then return the number of charsets. */
1106 UINT FASTCALL IntGetCharSet(INT nIndex, FT_ULong CodePageRange1)
1107 {
1108  UINT BitIndex, CharSet;
1109  UINT nCount = 0;
1110 
1111  if (CodePageRange1 == 0)
1112  {
1113  return (nIndex < 0) ? 1 : DEFAULT_CHARSET;
1114  }
1115 
1116  for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
1117  {
1118  if (CodePageRange1 & (1 << BitIndex))
1119  {
1120  CharSet = g_FontTci[BitIndex].ciCharset;
1121  if ((nIndex >= 0) && (nCount == (UINT)nIndex))
1122  {
1123  return CharSet;
1124  }
1125  ++nCount;
1126  }
1127  }
1128 
1129  return (nIndex < 0) ? nCount : ANSI_CHARSET;
1130 }
1131 
1132 /* pixels to points */
1133 #define PX2PT(pixels) FT_MulDiv((pixels), 72, 96)
1134 
1135 static INT FASTCALL
1137 {
1138  FT_Error Error;
1140  PFONT_ENTRY_MEM PrivateEntry;
1141  PFONTGDI FontGDI;
1142  FT_Face Face;
1143  NTSTATUS Status;
1145  FT_WinFNT_HeaderRec WinFNT;
1146  PUNICODE_STRING pFileName = pLoadFont->pFileName;
1147  DWORD Characteristics = pLoadFont->Characteristics;
1148  PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
1149  TT_OS2 * pOS2;
1150  FT_ULong os2_ulCodePageRange1;
1151  PSHARED_FACE SharedFace;
1152  INT iCharSet, CharSetCount;
1154  LIST_ENTRY LoadedFontList;
1155  USHORT NameLength;
1156  SIZE_T Length;
1157  PWCHAR pszBuffer;
1158  UNICODE_STRING NewString;
1159  WCHAR szSize[32];
1160 
1161  /* Retrieve the number of faces */
1162  IntLockFreeType();
1164  pLoadFont->Memory->Buffer,
1165  pLoadFont->Memory->BufferSize,
1166  -1,
1167  &Face);
1168  if (!Error)
1169  {
1170  FaceCount = Face->num_faces;
1171  FT_Done_Face(Face);
1172  }
1174 
1175  if (Error)
1176  {
1177  UNICODE_STRING MemoryFont = RTL_CONSTANT_STRING(L"MemoryFont");
1178  PUNICODE_STRING PrintFile = pFileName ? pFileName : &MemoryFont;
1179  if (Error == FT_Err_Unknown_File_Format)
1180  DPRINT1("Unknown font file format (%wZ)\n", PrintFile);
1181  else
1182  DPRINT1("Error reading font (FT_Error: %d, %wZ)\n", Error, PrintFile);
1183  return 0; /* failure */
1184  }
1185 
1186  /*
1187  * Initialize the temporary font list that needs to be appended to the
1188  * global or per-process font table, in case font enumeration successes.
1189  * If an error happens while loading and enumerating the fonts, this list
1190  * is used to cleanup the allocated resources.
1191  */
1192  InitializeListHead(&LoadedFontList);
1193 
1194  /*
1195  * Enumerate each typeface in the font.
1196  */
1197  for (iFace = 0; iFace < FaceCount; ++iFace)
1198  {
1199  Face = NULL;
1200  SharedFace = NULL;
1201 
1202  IntLockFreeType();
1204  pLoadFont->Memory->Buffer,
1205  pLoadFont->Memory->BufferSize,
1206  iFace,
1207  &Face);
1208  if (!Error)
1209  {
1210  SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
1211  }
1213 
1214  if (Error || !SharedFace)
1215  {
1216  DPRINT1("Error reading font (FT_Error: %d)\n", Error);
1217  goto Finish; /* failure */
1218  }
1219 
1220  /* os2_ulCodePageRange1 and CharSetCount and IsTrueType */
1221  os2_ulCodePageRange1 = 0;
1222  if (FT_IS_SFNT(Face))
1223  {
1224  IntLockFreeType();
1225  pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
1226  if (pOS2)
1227  {
1228  os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
1229  }
1231 
1232  CharSetCount = IntGetCharSet(-1, os2_ulCodePageRange1);
1233  pLoadFont->IsTrueType = TRUE;
1234  }
1235  else
1236  {
1237  CharSetCount = 1;
1238  pLoadFont->IsTrueType = FALSE;
1239  }
1240 
1241  /*
1242  * Enumerate all supported character sets for the selected typeface.
1243  */
1244  for (iCharSet = 0; iCharSet < CharSetCount; ++iCharSet)
1245  {
1246  /*
1247  * Add a reference to SharedFace only when iCharSet is > 0,
1248  * since the first reference has been already done by the
1249  * SharedFace_Create() call above.
1250  */
1251  if (iCharSet > 0)
1252  {
1253  IntLockFreeType();
1254  SharedFace_AddRef(SharedFace);
1256  }
1257 
1258  /* Allocate a FONT_ENTRY */
1260  if (!Entry)
1261  {
1262  DPRINT1("Failed to allocate FONT_ENTRY\n");
1263  SharedFace_Release(SharedFace);
1265  goto Finish; /* failure */
1266  }
1267 
1268  /* Allocate a FONTGDI */
1269  FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
1270  if (!FontGDI)
1271  {
1272  DPRINT1("Failed to allocate FontGDI\n");
1273  SharedFace_Release(SharedFace);
1276  goto Finish; /* failure */
1277  }
1278 
1279  /* Set face */
1280  FontGDI->SharedFace = SharedFace;
1281  FontGDI->CharSet = ANSI_CHARSET;
1282  FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name);
1283  FontGDI->RequestItalic = FALSE;
1284  FontGDI->OriginalWeight = WeightFromStyle(Face->style_name);
1285  FontGDI->RequestWeight = FW_NORMAL;
1286 
1287  /* Entry->FaceName */
1290  if (!NT_SUCCESS(Status))
1291  {
1292  DPRINT1("Failed to allocate Entry->FaceName\n");
1293  CleanupFontEntryEx(Entry, FontGDI);
1295  goto Finish; /* failure */
1296  }
1297 
1298  /* Entry->StyleName */
1299  RtlInitUnicodeString(&Entry->StyleName, NULL);
1300  if (Face->style_name && Face->style_name[0] &&
1301  strcmp(Face->style_name, "Regular") != 0)
1302  {
1305  if (!NT_SUCCESS(Status))
1306  {
1307  DPRINT1("Failed to allocate Entry->StyleName\n");
1308  CleanupFontEntryEx(Entry, FontGDI);
1310  goto Finish; /* failure */
1311  }
1312  }
1313 
1314  /* FontGDI->CharSet */
1315  if (FT_IS_SFNT(Face))
1316  {
1317  FontGDI->CharSet = IntGetCharSet(iCharSet, os2_ulCodePageRange1);
1318  }
1319  else
1320  {
1321  IntLockFreeType();
1322  Error = FT_Get_WinFNT_Header(Face, &WinFNT);
1323  if (!Error)
1324  {
1325  FontGDI->CharSet = WinFNT.charset;
1326  pLoadFont->CharSet = WinFNT.charset;
1327  }
1329  }
1330 
1331  /* Set the file name */
1332  if (pFileName)
1333  {
1334  // TODO: Since this Filename is common to all the faces+charsets
1335  // inside the given font, it may be worth to somehow cache it
1336  // only once and share it amongst all these faces+charsets.
1337 
1338  Length = pFileName->Length + sizeof(UNICODE_NULL);
1340  if (FontGDI->Filename == NULL)
1341  {
1342  DPRINT1("Failed to allocate FontGDI->Filename\n");
1343  CleanupFontEntryEx(Entry, FontGDI);
1345  goto Finish; /* failure */
1346  }
1347  IntUnicodeStringToBuffer(FontGDI->Filename, Length, pFileName);
1348  }
1349  else
1350  {
1351  /* This is a memory font, initialize a suitable entry */
1352 
1353  FontGDI->Filename = NULL;
1354 
1355  PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT);
1356  if (!PrivateEntry)
1357  {
1358  DPRINT1("Failed to allocate PrivateEntry\n");
1359  CleanupFontEntryEx(Entry, FontGDI);
1361  goto Finish; /* failure */
1362  }
1363 
1364  PrivateEntry->Entry = Entry;
1365  if (pLoadFont->PrivateEntry)
1366  {
1367  InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry);
1368  }
1369  else
1370  {
1371  InitializeListHead(&PrivateEntry->ListEntry);
1372  pLoadFont->PrivateEntry = PrivateEntry;
1373  }
1374  }
1375 
1376  /* Add this font resource to the font table */
1377  Entry->Font = FontGDI;
1378  Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
1379  InsertTailList(&LoadedFontList, &Entry->ListEntry);
1380 
1381  DPRINT("Font loaded: %s (%s), CharSet %u, Num glyphs %d\n",
1382  Face->family_name, Face->style_name, FontGDI->CharSet, Face->num_glyphs);
1383  }
1384 
1385  IntLockFreeType();
1386  /* Error = */ IntRequestFontSize(NULL, FontGDI, 0, 0);
1388 
1389  /*
1390  * Initialize and build the registry font value entry,
1391  * only in the case we load fonts from a file and not from memory.
1392  */
1393  if (!pFileName)
1394  continue;
1395  NameLength = Entry->FaceName.Length;
1396  if (pValueName->Length == 0)
1397  {
1398  if (FT_IS_SFNT(Face))
1399  {
1400  // L"Name StyleName\0"
1401  Length = NameLength + sizeof(L' ') + Entry->StyleName.Length + sizeof(UNICODE_NULL);
1403  if (pszBuffer)
1404  {
1405  RtlInitEmptyUnicodeString(pValueName, pszBuffer, Length);
1406  RtlCopyUnicodeString(pValueName, &Entry->FaceName);
1407  if (Entry->StyleName.Length > 0)
1408  {
1409  RtlAppendUnicodeToString(pValueName, L" ");
1410  RtlAppendUnicodeStringToString(pValueName, &Entry->StyleName);
1411  }
1412  }
1413  else
1414  {
1415  break; /* failure */
1416  }
1417  }
1418  else
1419  {
1420  szSize[0] = L' ';
1421  _itow(PX2PT(FontGDI->EmHeight), szSize+1, 10);
1422 
1423  Length = NameLength + (wcslen(szSize) + 1) * sizeof(WCHAR);
1425  if (pszBuffer)
1426  {
1427  RtlInitEmptyUnicodeString(pValueName, pszBuffer, Length);
1428  RtlCopyUnicodeString(pValueName, &Entry->FaceName);
1429  RtlAppendUnicodeToString(pValueName, szSize);
1430  }
1431  else
1432  {
1433  break; /* failure */
1434  }
1435  }
1436  }
1437  else
1438  {
1439  if (FT_IS_SFNT(Face))
1440  {
1441  // L"... & Name StyleName\0"
1442  Length = pValueName->Length + 3 * sizeof(WCHAR) + Entry->FaceName.Length +
1443  sizeof(L' ') + Entry->StyleName.Length + sizeof(UNICODE_NULL);
1445  if (pszBuffer)
1446  {
1447  RtlInitEmptyUnicodeString(&NewString, pszBuffer, Length);
1448  RtlCopyUnicodeString(&NewString, pValueName);
1449  RtlAppendUnicodeToString(&NewString, L" & ");
1450  RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
1451  if (Entry->StyleName.Length > 0)
1452  {
1453  RtlAppendUnicodeToString(&NewString, L" ");
1454  RtlAppendUnicodeStringToString(&NewString, &Entry->StyleName);
1455  }
1456  }
1457  else
1458  {
1459  RtlFreeUnicodeString(pValueName);
1460  break; /* failure */
1461  }
1462  }
1463  else
1464  {
1465  szSize[0] = L',';
1466  _itow(PX2PT(FontGDI->EmHeight), szSize+1, 10);
1467 
1468  Length = pValueName->Length + (wcslen(szSize) + 1) * sizeof(WCHAR);
1470  if (pszBuffer)
1471  {
1472  RtlInitEmptyUnicodeString(&NewString, pszBuffer, Length);
1473  RtlCopyUnicodeString(&NewString, pValueName);
1474  RtlAppendUnicodeToString(&NewString, szSize);
1475  }
1476  else
1477  {
1478  RtlFreeUnicodeString(pValueName);
1479  break; /* failure */
1480  }
1481  }
1482 
1483  RtlFreeUnicodeString(pValueName);
1484  *pValueName = NewString;
1485  }
1486  }
1487 
1488 Finish:
1489  if (iFace == FaceCount)
1490  {
1491  /*
1492  * We succeeded, append the created font entries into the correct font table.
1493  */
1494  PLIST_ENTRY ListToAppend;
1495 
1496  /* No typefaces were present */
1497  if (FaceCount == 0)
1498  {
1499  ASSERT(IsListEmpty(&LoadedFontList));
1500  return 0;
1501  }
1502 
1503  ASSERT(!IsListEmpty(&LoadedFontList));
1504 
1505  /*
1506  * Remove the temporary font list' head and reinitialize it.
1507  * This effectively empties the list and at the same time transforms
1508  * 'ListToAppend' into a headless list, ready to be appended to the
1509  * suitable font table.
1510  */
1511  ListToAppend = LoadedFontList.Flink;
1512  RemoveEntryList(&LoadedFontList);
1513  InitializeListHead(&LoadedFontList);
1514 
1515  if (Characteristics & FR_PRIVATE)
1516  {
1517  /* Private font */
1519  IntLockProcessPrivateFonts(Win32Process);
1520  AppendTailList(&Win32Process->PrivateFontListHead, ListToAppend);
1521  IntUnLockProcessPrivateFonts(Win32Process);
1522  }
1523  else
1524  {
1525  /* Global font */
1527  AppendTailList(&g_FontListHead, ListToAppend);
1529  }
1530 
1531  return FaceCount; /* Number of loaded faces */
1532  }
1533  else
1534  {
1535  /* We failed, cleanup the resources */
1536  PLIST_ENTRY ListEntry;
1537 
1538  if (pLoadFont->PrivateEntry)
1539  {
1540  while (!IsListEmpty(&pLoadFont->PrivateEntry->ListEntry))
1541  {
1542  ListEntry = RemoveHeadList(&pLoadFont->PrivateEntry->ListEntry);
1543  PrivateEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
1544  ExFreePoolWithTag(PrivateEntry, TAG_FONT);
1545  }
1547  pLoadFont->PrivateEntry = NULL;
1548  }
1549 
1550  while (!IsListEmpty(&LoadedFontList))
1551  {
1552  ListEntry = RemoveHeadList(&LoadedFontList);
1553  Entry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
1555  }
1556 
1557  return 0; /* No faces have been added */
1558  }
1559 }
1560 
1561 static LPCWSTR FASTCALL
1563 {
1564  switch (CharSet)
1565  {
1566  case ANSI_CHARSET: return L"ANSI";
1567  case DEFAULT_CHARSET: return L"Default";
1568  case SYMBOL_CHARSET: return L"Symbol";
1569  case SHIFTJIS_CHARSET: return L"Shift_JIS";
1570  case HANGUL_CHARSET: return L"Hangul";
1571  case GB2312_CHARSET: return L"GB 2312";
1572  case CHINESEBIG5_CHARSET: return L"Chinese Big5";
1573  case OEM_CHARSET: return L"OEM";
1574  case JOHAB_CHARSET: return L"Johab";
1575  case HEBREW_CHARSET: return L"Hebrew";
1576  case ARABIC_CHARSET: return L"Arabic";
1577  case GREEK_CHARSET: return L"Greek";
1578  case TURKISH_CHARSET: return L"Turkish";
1579  case VIETNAMESE_CHARSET: return L"Vietnamese";
1580  case THAI_CHARSET: return L"Thai";
1581  case EASTEUROPE_CHARSET: return L"Eastern European";
1582  case RUSSIAN_CHARSET: return L"Russian";
1583  case MAC_CHARSET: return L"Mac";
1584  case BALTIC_CHARSET: return L"Baltic";
1585  default: return L"Unknown";
1586  }
1587 }
1588 
1589 /*
1590  * IntGdiAddFontResource
1591  *
1592  * Adds the font resource from the specified file to the system.
1593  */
1594 
1595 INT FASTCALL
1597  DWORD dwFlags)
1598 {
1599  NTSTATUS Status;
1601  PVOID Buffer = NULL;
1604  SIZE_T ViewSize = 0, Length;
1605  LARGE_INTEGER SectionSize;
1608  INT FontCount;
1609  HANDLE KeyHandle;
1610  UNICODE_STRING PathName;
1611  LPWSTR pszBuffer;
1613  static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
1614  static const UNICODE_STRING DosPathPrefix = RTL_CONSTANT_STRING(L"\\??\\");
1615 
1616  /* Build PathName */
1618  {
1619  Length = DosPathPrefix.Length + FileName->Length + sizeof(UNICODE_NULL);
1621  if (!pszBuffer)
1622  return 0; /* failure */
1623 
1624  RtlInitEmptyUnicodeString(&PathName, pszBuffer, Length);
1625  RtlAppendUnicodeStringToString(&PathName, &DosPathPrefix);
1627  }
1628  else
1629  {
1630  Status = DuplicateUnicodeString(FileName, &PathName);
1631  if (!NT_SUCCESS(Status))
1632  return 0; /* failure */
1633  }
1634 
1635  /* Open the font file */
1638  Status = ZwOpenFile(
1639  &FileHandle,
1642  &Iosb,
1645  if (!NT_SUCCESS(Status))
1646  {
1647  DPRINT1("Could not load font file: %wZ\n", &PathName);
1648  RtlFreeUnicodeString(&PathName);
1649  return 0;
1650  }
1651 
1654  if (!NT_SUCCESS(Status))
1655  {
1656  DPRINT1("ObReferenceObjectByHandle failed.\n");
1658  RtlFreeUnicodeString(&PathName);
1659  return 0;
1660  }
1661 
1662  SectionSize.QuadPart = 0LL;
1665  NULL, &SectionSize, PAGE_READONLY,
1667  if (!NT_SUCCESS(Status))
1668  {
1669  DPRINT1("Could not map file: %wZ\n", &PathName);
1672  RtlFreeUnicodeString(&PathName);
1673  return 0;
1674  }
1676 
1678  if (!NT_SUCCESS(Status))
1679  {
1680  DPRINT1("Could not map file: %wZ\n", &PathName);
1683  RtlFreeUnicodeString(&PathName);
1684  return 0;
1685  }
1686 
1687  LoadFont.pFileName = &PathName;
1689  LoadFont.Characteristics = Characteristics;
1690  RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1691  LoadFont.IsTrueType = FALSE;
1692  LoadFont.CharSet = DEFAULT_CHARSET;
1693  LoadFont.PrivateEntry = NULL;
1694  FontCount = IntGdiLoadFontsFromMemory(&LoadFont);
1695 
1696  /* Release our copy */
1697  IntLockFreeType();
1698  SharedMem_Release(LoadFont.Memory);
1700 
1702 
1704 
1705  /* Save the loaded font name into the registry */
1706  if (FontCount > 0 && (dwFlags & AFRX_WRITE_REGISTRY))
1707  {
1708  UNICODE_STRING NewString;
1709  SIZE_T Length;
1710  PWCHAR pszBuffer;
1711  LPCWSTR CharSetName;
1712  if (LoadFont.IsTrueType)
1713  {
1714  /* Append " (TrueType)" */
1715  Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length + sizeof(UNICODE_NULL);
1717  if (pszBuffer)
1718  {
1719  RtlInitEmptyUnicodeString(&NewString, pszBuffer, Length);
1720  NewString.Buffer[0] = UNICODE_NULL;
1721  RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
1722  RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
1723  RtlFreeUnicodeString(&LoadFont.RegValueName);
1724  LoadFont.RegValueName = NewString;
1725  }
1726  else
1727  {
1728  // FIXME!
1729  }
1730  }
1731  else if (LoadFont.CharSet != DEFAULT_CHARSET)
1732  {
1733  /* Append " (CharSetName)" */
1734  CharSetName = NameFromCharSet(LoadFont.CharSet);
1735  Length = LoadFont.RegValueName.Length +
1736  (wcslen(CharSetName) + 3) * sizeof(WCHAR) +
1737  sizeof(UNICODE_NULL);
1738 
1740  if (pszBuffer)
1741  {
1742  RtlInitEmptyUnicodeString(&NewString, pszBuffer, Length);
1743  NewString.Buffer[0] = UNICODE_NULL;
1744  RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
1745  RtlAppendUnicodeToString(&NewString, L" (");
1746  RtlAppendUnicodeToString(&NewString, CharSetName);
1747  RtlAppendUnicodeToString(&NewString, L")");
1748  RtlFreeUnicodeString(&LoadFont.RegValueName);
1749  LoadFont.RegValueName = NewString;
1750  }
1751  else
1752  {
1753  // FIXME!
1754  }
1755  }
1756 
1759  NULL, NULL);
1760  Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
1761  if (NT_SUCCESS(Status))
1762  {
1763  SIZE_T DataSize;
1764  LPWSTR pFileName;
1765 
1767  {
1768  pFileName = PathName.Buffer;
1769  }
1770  else
1771  {
1772  pFileName = wcsrchr(PathName.Buffer, L'\\');
1773  }
1774 
1775  if (pFileName)
1776  {
1777  if (!(dwFlags & AFRX_ALTERNATIVE_PATH))
1778  {
1779  pFileName++;
1780  }
1781  DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
1782  ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
1783  pFileName, DataSize);
1784  }
1785  ZwClose(KeyHandle);
1786  }
1787  }
1788  RtlFreeUnicodeString(&LoadFont.RegValueName);
1789 
1790  RtlFreeUnicodeString(&PathName);
1791  return FontCount;
1792 }
1793 
1794 INT FASTCALL
1796 {
1797  return IntGdiAddFontResourceEx(FileName, Characteristics, 0);
1798 }
1799 
1800 /* Borrowed from shlwapi!PathIsRelativeW */
1802 {
1803  if (!lpszPath || !*lpszPath)
1804  return TRUE;
1805  if (*lpszPath == L'\\' || (*lpszPath && lpszPath[1] == L':'))
1806  return FALSE;
1807  return TRUE;
1808 }
1809 
1810 BOOL FASTCALL
1812 {
1813  NTSTATUS Status;
1814  HANDLE KeyHandle;
1816  KEY_FULL_INFORMATION KeyFullInfo;
1817  ULONG i, Length;
1818  UNICODE_STRING FontTitleW, FileNameW;
1819  SIZE_T InfoSize;
1820  LPBYTE InfoBuffer;
1822  LPWSTR pchPath;
1823  BOOLEAN Success;
1825  INT nFontCount = 0;
1826  DWORD dwFlags;
1827 
1828  /* open registry key */
1831  NULL, NULL);
1832  Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
1833  if (!NT_SUCCESS(Status))
1834  {
1835  DPRINT1("ZwOpenKey failed: 0x%08X\n", Status);
1836  return FALSE; /* failure */
1837  }
1838 
1839  /* query count of values */
1840  Status = ZwQueryKey(KeyHandle, KeyFullInformation,
1841  &KeyFullInfo, sizeof(KeyFullInfo), &Length);
1842  if (!NT_SUCCESS(Status))
1843  {
1844  DPRINT1("ZwQueryKey failed: 0x%08X\n", Status);
1845  ZwClose(KeyHandle);
1846  return FALSE; /* failure */
1847  }
1848 
1849  /* allocate buffer */
1850  InfoSize = (MAX_PATH + 256) * sizeof(WCHAR);
1851  InfoBuffer = ExAllocatePoolWithTag(PagedPool, InfoSize, TAG_FONT);
1852  if (!InfoBuffer)
1853  {
1854  DPRINT1("ExAllocatePoolWithTag failed\n");
1855  ZwClose(KeyHandle);
1856  return FALSE;
1857  }
1858 
1859  /* for each value */
1860  for (i = 0; i < KeyFullInfo.Values; ++i)
1861  {
1862  /* get value name */
1863  Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
1864  InfoBuffer, InfoSize, &Length);
1866  {
1867  /* too short buffer */
1868  ExFreePoolWithTag(InfoBuffer, TAG_FONT);
1869  InfoSize *= 2;
1870  InfoBuffer = ExAllocatePoolWithTag(PagedPool, InfoSize, TAG_FONT);
1871  if (!InfoBuffer)
1872  {
1873  DPRINT1("ExAllocatePoolWithTag failed\n");
1874  break;
1875  }
1876  /* try again */
1877  Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
1878  InfoBuffer, InfoSize, &Length);
1879  }
1880  if (!NT_SUCCESS(Status))
1881  {
1882  DPRINT1("ZwEnumerateValueKey failed: 0x%08X\n", Status);
1883  break; /* failure */
1884  }
1885 
1886  /* create FontTitleW string */
1887  pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
1888  Length = pInfo->NameLength / sizeof(WCHAR);
1889  pInfo->Name[Length] = UNICODE_NULL; /* truncate */
1890  Success = RtlCreateUnicodeString(&FontTitleW, pInfo->Name);
1891  if (!Success)
1892  {
1894  DPRINT1("RtlCreateUnicodeString failed\n");
1895  break; /* failure */
1896  }
1897 
1898  /* query value */
1899  Status = ZwQueryValueKey(KeyHandle, &FontTitleW, KeyValueFullInformation,
1900  InfoBuffer, InfoSize, &Length);
1902  {
1903  /* too short buffer */
1904  ExFreePoolWithTag(InfoBuffer, TAG_FONT);
1905  InfoSize *= 2;
1906  InfoBuffer = ExAllocatePoolWithTag(PagedPool, InfoSize, TAG_FONT);
1907  if (!InfoBuffer)
1908  {
1909  DPRINT1("ExAllocatePoolWithTag failed\n");
1910  break;
1911  }
1912  /* try again */
1913  Status = ZwQueryValueKey(KeyHandle, &FontTitleW, KeyValueFullInformation,
1914  InfoBuffer, InfoSize, &Length);
1915  }
1916  pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
1917  if (!NT_SUCCESS(Status) || !pInfo->DataLength)
1918  {
1919  DPRINT1("ZwQueryValueKey failed: 0x%08X\n", Status);
1920  RtlFreeUnicodeString(&FontTitleW);
1921  break; /* failure */
1922  }
1923 
1924  /* Build pchPath */
1925  pchPath = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
1926  Length = pInfo->DataLength / sizeof(WCHAR);
1927  pchPath[Length] = UNICODE_NULL; /* truncate */
1928 
1929  /* Load font(s) without writing registry */
1930  if (PathIsRelativeW(pchPath))
1931  {
1932  dwFlags = 0;
1934  L"\\SystemRoot\\Fonts\\%s", pchPath);
1935  }
1936  else
1937  {
1939  Status = RtlStringCbCopyW(szPath, sizeof(szPath), pchPath);
1940  }
1941 
1942  if (NT_SUCCESS(Status))
1943  {
1944  RtlCreateUnicodeString(&FileNameW, szPath);
1945  nFontCount += IntGdiAddFontResourceEx(&FileNameW, 0, dwFlags);
1946  RtlFreeUnicodeString(&FileNameW);
1947  }
1948 
1949  RtlFreeUnicodeString(&FontTitleW);
1950  }
1951 
1952  /* close now */
1953  ZwClose(KeyHandle);
1954 
1955  /* free memory block */
1956  if (InfoBuffer)
1957  {
1958  ExFreePoolWithTag(InfoBuffer, TAG_FONT);
1959  }
1960 
1961  return (KeyFullInfo.Values != 0 && nFontCount != 0);
1962 }
1963 
1966 {
1967  HANDLE Ret = NULL;
1969  PFONT_ENTRY_COLL_MEM EntryCollection;
1970  INT FaceCount;
1971 
1973  if (!BufferCopy)
1974  {
1975  *pNumAdded = 0;
1976  return NULL;
1977  }
1978  RtlCopyMemory(BufferCopy, Buffer, dwSize);
1979 
1980  LoadFont.pFileName = NULL;
1981  LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
1982  LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
1983  RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1984  LoadFont.IsTrueType = FALSE;
1985  LoadFont.PrivateEntry = NULL;
1987 
1988  RtlFreeUnicodeString(&LoadFont.RegValueName);
1989 
1990  /* Release our copy */
1991  IntLockFreeType();
1992  SharedMem_Release(LoadFont.Memory);
1994 
1995  if (FaceCount > 0)
1996  {
1997  EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
1998  if (EntryCollection)
1999  {
2001  EntryCollection->Entry = LoadFont.PrivateEntry;
2002  IntLockProcessPrivateFonts(Win32Process);
2003  EntryCollection->Handle = ULongToHandle(++Win32Process->PrivateMemFontHandleCount);
2004  InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
2005  IntUnLockProcessPrivateFonts(Win32Process);
2006  Ret = EntryCollection->Handle;
2007  }
2008  }
2009  *pNumAdded = FaceCount;
2010 
2011  return Ret;
2012 }
2013 
2014 // FIXME: Add RemoveFontResource
2015 
2016 VOID FASTCALL
2018 {
2020  PFONT_ENTRY_MEM FontEntry;
2021 
2022  while (!IsListEmpty(&Head->ListEntry))
2023  {
2024  Entry = RemoveHeadList(&Head->ListEntry);
2025  FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
2026 
2027  CleanupFontEntry(FontEntry->Entry);
2028  ExFreePoolWithTag(FontEntry, TAG_FONT);
2029  }
2030 
2031  CleanupFontEntry(Head->Entry);
2032  ExFreePoolWithTag(Head, TAG_FONT);
2033 }
2034 
2035 static VOID FASTCALL
2037 {
2038  PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
2039  PLIST_ENTRY ListEntry;
2040  RemoveEntryList(&Collection->ListEntry);
2041 
2042  do {
2043  /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
2044  RemoveEntryList(&FontMemEntry->Entry->ListEntry);
2045 
2046  ListEntry = FontMemEntry->ListEntry.Flink;
2047  FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
2048 
2049  } while (FontMemEntry != Collection->Entry);
2050 }
2051 
2052 BOOL FASTCALL
2054 {
2056  PFONT_ENTRY_COLL_MEM CurrentEntry;
2057  PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
2059 
2060  IntLockProcessPrivateFonts(Win32Process);
2061  for (Entry = Win32Process->PrivateMemFontListHead.Flink;
2062  Entry != &Win32Process->PrivateMemFontListHead;
2063  Entry = Entry->Flink)
2064  {
2065  CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
2066 
2067  if (CurrentEntry->Handle == hMMFont)
2068  {
2069  EntryCollection = CurrentEntry;
2070  UnlinkFontMemCollection(CurrentEntry);
2071  break;
2072  }
2073  }
2074  IntUnLockProcessPrivateFonts(Win32Process);
2075 
2076  if (EntryCollection)
2077  {
2078  IntGdiCleanupMemEntry(EntryCollection->Entry);
2079  ExFreePoolWithTag(EntryCollection, TAG_FONT);
2080  return TRUE;
2081  }
2082  return FALSE;
2083 }
2084 
2085 
2086 VOID FASTCALL
2088 {
2091  PFONT_ENTRY_COLL_MEM EntryCollection;
2092 
2093  DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
2094  do {
2095  Entry = NULL;
2096  EntryCollection = NULL;
2097 
2098  IntLockProcessPrivateFonts(Win32Process);
2099  if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
2100  {
2101  Entry = Win32Process->PrivateMemFontListHead.Flink;
2102  EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
2103  UnlinkFontMemCollection(EntryCollection);
2104  }
2105  IntUnLockProcessPrivateFonts(Win32Process);
2106 
2107  if (EntryCollection)
2108  {
2109  IntGdiCleanupMemEntry(EntryCollection->Entry);
2110  ExFreePoolWithTag(EntryCollection, TAG_FONT);
2111  }
2112  else
2113  {
2114  /* No Mem fonts anymore, see if we have any other private fonts left */
2115  Entry = NULL;
2116  IntLockProcessPrivateFonts(Win32Process);
2117  if (!IsListEmpty(&Win32Process->PrivateFontListHead))
2118  {
2119  Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
2120  }
2121  IntUnLockProcessPrivateFonts(Win32Process);
2122 
2123  if (Entry)
2124  {
2126  }
2127  }
2128 
2129  } while (Entry);
2130 }
2131 
2132 BOOL FASTCALL
2134 {
2135  return (gpsi->BitsPixel > 8) && g_RenderingEnabled;
2136 }
2137 
2138 VOID FASTCALL
2140 {
2142 }
2143 
2146 {
2147  switch (logfont->lfQuality)
2148  {
2149  case ANTIALIASED_QUALITY:
2150  break;
2152  return FT_RENDER_MODE_MONO;
2153  case DRAFT_QUALITY:
2154  return FT_RENDER_MODE_LIGHT;
2155  case CLEARTYPE_QUALITY:
2156  if (!gspv.bFontSmoothing)
2157  break;
2159  break;
2160  return FT_RENDER_MODE_LCD;
2161  }
2162  return FT_RENDER_MODE_NORMAL;
2163 }
2164 
2165 
2168 {
2169  PLFONT plfont;
2170  LOGFONTW *plf;
2171 
2172  ASSERT(lf);
2173  plfont = LFONT_AllocFontWithHandle();
2174  if (!plfont)
2175  {
2176  return STATUS_NO_MEMORY;
2177  }
2178 
2179  ExInitializePushLock(&plfont->lock);
2180  *NewFont = plfont->BaseObject.hHmgr;
2181  plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
2182  RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
2183  if (lf->lfEscapement != lf->lfOrientation)
2184  {
2185  /* This should really depend on whether GM_ADVANCED is set */
2186  plf->lfOrientation = plf->lfEscapement;
2187  }
2188  LFONT_UnlockFont(plfont);
2189 
2190  return STATUS_SUCCESS;
2191 }
2192 
2193 /*************************************************************************
2194  * TranslateCharsetInfo
2195  *
2196  * Fills a CHARSETINFO structure for a character set, code page, or
2197  * font. This allows making the correspondance between different labelings
2198  * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2199  * of the same encoding.
2200  *
2201  * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
2202  * only one codepage should be set in *Src.
2203  *
2204  * RETURNS
2205  * TRUE on success, FALSE on failure.
2206  *
2207  */
2208 static BOOLEAN APIENTRY
2210  if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2211  if flags == TCI_SRCCHARSET: a character set value
2212  if flags == TCI_SRCCODEPAGE: a code page value */
2213  LPCHARSETINFO Cs, /* [out] structure to receive charset information */
2214  DWORD Flags /* [in] determines interpretation of lpSrc */)
2215 {
2216  int Index = 0;
2217 
2218  switch (Flags)
2219  {
2220  case TCI_SRCFONTSIG:
2221  while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
2222  {
2223  Index++;
2224  }
2225  break;
2226  case TCI_SRCCODEPAGE:
2227  while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciACP)
2228  {
2229  Index++;
2230  }
2231  break;
2232  case TCI_SRCCHARSET:
2233  while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciCharset)
2234  {
2235  Index++;
2236  }
2237  break;
2238  case TCI_SRCLOCALE:
2239  UNIMPLEMENTED;
2240  return FALSE;
2241  default:
2242  return FALSE;
2243  }
2244 
2245  if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == g_FontTci[Index].ciCharset)
2246  {
2247  return FALSE;
2248  }
2249 
2250  RtlCopyMemory(Cs, &g_FontTci[Index], sizeof(CHARSETINFO));
2251 
2252  return TRUE;
2253 }
2254 
2255 
2257 {
2258  int i;
2259 
2260  for(i = 0; i < ft_face->num_charmaps; i++)
2261  {
2262  if (ft_face->charmaps[i]->platform_id == TT_PLATFORM_MICROSOFT &&
2263  ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
2264  {
2265  return TRUE;
2266  }
2267  }
2268  return FALSE;
2269 }
2270 
2271 static void FASTCALL
2273  TT_OS2 *pOS2, TT_HoriHeader *pHori,
2274  FT_WinFNT_HeaderRec *pFNT, BOOL RealFont)
2275 {
2276  FT_Fixed XScale, YScale;
2277  int Ascent, Descent;
2278  FT_Face Face = FontGDI->SharedFace->Face;
2279 
2281 
2282  XScale = Face->size->metrics.x_scale;
2283  YScale = Face->size->metrics.y_scale;
2284 
2285  if (pFNT)
2286  {
2287  TM->tmHeight = pFNT->pixel_height;
2288  TM->tmAscent = pFNT->ascent;
2289  TM->tmDescent = TM->tmHeight - TM->tmAscent;
2290  TM->tmInternalLeading = pFNT->internal_leading;
2291  TM->tmExternalLeading = pFNT->external_leading;
2292  TM->tmAveCharWidth = pFNT->avg_width;
2293  TM->tmMaxCharWidth = pFNT->max_width;
2294  TM->tmOverhang = 0;
2297  TM->tmFirstChar = pFNT->first_char;
2298  TM->tmLastChar = pFNT->last_char;
2299  TM->tmDefaultChar = pFNT->default_char + pFNT->first_char;
2300  TM->tmBreakChar = pFNT->break_char + pFNT->first_char;
2301  TM->tmPitchAndFamily = pFNT->pitch_and_family;
2302  if (RealFont)
2303  {
2304  TM->tmWeight = FontGDI->OriginalWeight;
2305  TM->tmItalic = FontGDI->OriginalItalic;
2306  TM->tmUnderlined = pFNT->underline;
2307  TM->tmStruckOut = pFNT->strike_out;
2308  TM->tmCharSet = pFNT->charset;
2309  }
2310  else
2311  {
2312  TM->tmWeight = FontGDI->RequestWeight;
2313  TM->tmItalic = FontGDI->RequestItalic;
2314  TM->tmUnderlined = FontGDI->RequestUnderline;
2315  TM->tmStruckOut = FontGDI->RequestStrikeOut;
2316  TM->tmCharSet = FontGDI->CharSet;
2317  }
2318  return;
2319  }
2320 
2321  if ((FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent == 0)
2322  {
2323  Ascent = pHori->Ascender;
2324  Descent = -pHori->Descender;
2325  }
2326  else
2327  {
2328  Ascent = (FT_Short)pOS2->usWinAscent;
2329  Descent = (FT_Short)pOS2->usWinDescent;
2330  }
2331 
2332  TM->tmAscent = FontGDI->tmAscent;
2333  TM->tmDescent = FontGDI->tmDescent;
2334  TM->tmHeight = TM->tmAscent + TM->tmDescent;
2335  TM->tmInternalLeading = FontGDI->tmInternalLeading;
2336 
2337  /* MSDN says:
2338  * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2339  */
2340  TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
2341  - ((Ascent + Descent)
2342  - (pHori->Ascender - pHori->Descender)),
2343  YScale) + 32) >> 6);
2344 
2345  TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
2346  if (TM->tmAveCharWidth == 0)
2347  {
2348  TM->tmAveCharWidth = 1;
2349  }
2350 
2351  /* Correct forumla to get the maxcharwidth from unicode and ansi font */
2352  TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
2353 
2354  if (RealFont)
2355  {
2356  TM->tmWeight = FontGDI->OriginalWeight;
2357  }
2358  else
2359  {
2360  if (FontGDI->OriginalWeight != FW_DONTCARE &&
2361  FontGDI->OriginalWeight != FW_NORMAL)
2362  {
2363  TM->tmWeight = FontGDI->OriginalWeight;
2364  }
2365  else
2366  {
2367  TM->tmWeight = FontGDI->RequestWeight;
2368  }
2369  }
2370 
2371  TM->tmOverhang = 0;
2372  TM->tmDigitizedAspectX = 96;
2373  TM->tmDigitizedAspectY = 96;
2374  if (face_has_symbol_charmap(Face) ||
2375  (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
2376  {
2377  USHORT cpOEM, cpAnsi;
2378 
2379  EngGetCurrentCodePage(&cpOEM, &cpAnsi);
2380  TM->tmFirstChar = 0;
2381  switch(cpAnsi)
2382  {
2383  case 1257: /* Baltic */
2384  TM->tmLastChar = 0xf8fd;
2385  break;
2386  default:
2387  TM->tmLastChar = 0xf0ff;
2388  }
2389  TM->tmBreakChar = 0x20;
2390  TM->tmDefaultChar = 0x1f;
2391  }
2392  else
2393  {
2394  TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
2395  TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
2396 
2397  if(pOS2->usFirstCharIndex <= 1)
2398  TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
2399  else if (pOS2->usFirstCharIndex > 0xff)
2400  TM->tmBreakChar = 0x20;
2401  else
2402  TM->tmBreakChar = pOS2->usFirstCharIndex;
2403  TM->tmDefaultChar = TM->tmBreakChar - 1;
2404  }
2405 
2406  if (RealFont)
2407  {
2408  TM->tmItalic = FontGDI->OriginalItalic;
2409  TM->tmUnderlined = FALSE;
2410  TM->tmStruckOut = FALSE;
2411  }
2412  else
2413  {
2414  if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
2415  {
2416  TM->tmItalic = 0xFF;
2417  }
2418  else
2419  {
2420  TM->tmItalic = 0;
2421  }
2422  TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
2423  TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
2424  }
2425 
2426  if (!FT_IS_FIXED_WIDTH(Face))
2427  {
2428  switch (pOS2->panose[PAN_PROPORTION_INDEX])
2429  {
2430  case PAN_PROP_MONOSPACED:
2431  TM->tmPitchAndFamily = 0;
2432  break;
2433  default:
2435  break;
2436  }
2437  }
2438  else
2439  {
2440  TM->tmPitchAndFamily = 0;
2441  }
2442 
2443  switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
2444  {
2445  case PAN_FAMILY_SCRIPT:
2446  TM->tmPitchAndFamily |= FF_SCRIPT;
2447  break;
2448  case PAN_FAMILY_DECORATIVE:
2450  break;
2451 
2452  case PAN_ANY:
2453  case PAN_NO_FIT:
2455  case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
2456  /* Which is clearly not what the panose spec says. */
2457  if (TM->tmPitchAndFamily == 0) /* Fixed */
2458  {
2460  }
2461  else
2462  {
2463  switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
2464  {
2465  case PAN_ANY:
2466  case PAN_NO_FIT:
2467  default:
2469  break;
2470 
2471  case PAN_SERIF_COVE:
2472  case PAN_SERIF_OBTUSE_COVE:
2473  case PAN_SERIF_SQUARE_COVE:
2475  case PAN_SERIF_SQUARE:
2476  case PAN_SERIF_THIN:
2477  case PAN_SERIF_BONE:
2478  case PAN_SERIF_EXAGGERATED:
2479  case PAN_SERIF_TRIANGLE:
2480  TM->tmPitchAndFamily |= FF_ROMAN;
2481  break;
2482 
2483  case PAN_SERIF_NORMAL_SANS:
2484  case PAN_SERIF_OBTUSE_SANS:
2485  case PAN_SERIF_PERP_SANS:
2486  case PAN_SERIF_FLARED:
2487  case PAN_SERIF_ROUNDED:
2488  TM->tmPitchAndFamily |= FF_SWISS;
2489  break;
2490  }
2491  }
2492  break;
2493  default:
2495  }
2496 
2497  if (FT_IS_SCALABLE(Face))
2498  {
2500  }
2501  if (FT_IS_SFNT(Face))
2502  {
2504  }
2505 
2506  TM->tmCharSet = FontGDI->CharSet;
2507 }
2508 
2509 static void FASTCALL
2511  TT_OS2 *pOS2, TT_HoriHeader *pHori,
2512  FT_WinFNT_HeaderRec *pFNT)
2513 {
2514  FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
2515 }
2516 
2517 static NTSTATUS
2519  FT_UShort NameID, FT_UShort LangID);
2520 
2521 typedef struct FONT_NAMES
2522 {
2523  UNICODE_STRING FamilyNameW; /* family name (TT_NAME_ID_FONT_FAMILY) */
2524  UNICODE_STRING FaceNameW; /* face name (TT_NAME_ID_FULL_NAME) */
2525  UNICODE_STRING StyleNameW; /* style name (TT_NAME_ID_FONT_SUBFAMILY) */
2526  UNICODE_STRING FullNameW; /* unique name (TT_NAME_ID_UNIQUE_ID) */
2527  ULONG OtmSize; /* size of OUTLINETEXTMETRICW with extra data */
2529 
2530 static __inline void FASTCALL
2532 {
2533  ULONG OtmSize;
2534 
2535  RtlInitUnicodeString(&Names->FamilyNameW, NULL);
2536  RtlInitUnicodeString(&Names->FaceNameW, NULL);
2537  RtlInitUnicodeString(&Names->StyleNameW, NULL);
2538  RtlInitUnicodeString(&Names->FullNameW, NULL);
2539 
2540  /* family name */
2542  /* face name */
2544  /* style name */
2546  /* unique name (full name) */
2548 
2549  /* Calculate the size of OUTLINETEXTMETRICW with extra data */
2550  OtmSize = sizeof(OUTLINETEXTMETRICW) +
2551  Names->FamilyNameW.Length + sizeof(UNICODE_NULL) +
2552  Names->FaceNameW.Length + sizeof(UNICODE_NULL) +
2553  Names->StyleNameW.Length + sizeof(UNICODE_NULL) +
2554  Names->FullNameW.Length + sizeof(UNICODE_NULL);
2555  Names->OtmSize = OtmSize;
2556 }
2557 
2558 static __inline SIZE_T FASTCALL
2560 {
2561  RtlCopyMemory(pb, pName->Buffer, pName->Length);
2562  *(WCHAR *)&pb[pName->Length] = UNICODE_NULL;
2563  return pName->Length + sizeof(UNICODE_NULL);
2564 }
2565 
2566 static __inline BYTE *FASTCALL
2568 {
2569  BYTE *pb = (BYTE *)Otm + sizeof(OUTLINETEXTMETRICW);
2570 
2571  /* family name */
2572  Otm->otmpFamilyName = (LPSTR)(pb - (BYTE*) Otm);
2573  pb += IntStoreName(&Names->FamilyNameW, pb);
2574 
2575  /* face name */
2576  Otm->otmpFaceName = (LPSTR)(pb - (BYTE*) Otm);
2577  pb += IntStoreName(&Names->FaceNameW, pb);
2578 
2579  /* style name */
2580  Otm->otmpStyleName = (LPSTR)(pb - (BYTE*) Otm);
2581  pb += IntStoreName(&Names->StyleNameW, pb);
2582 
2583  /* unique name (full name) */
2584  Otm->otmpFullName = (LPSTR)(pb - (BYTE*) Otm);
2585  pb += IntStoreName(&Names->FullNameW, pb);
2586 
2587  return pb;
2588 }
2589 
2590 static __inline void FASTCALL
2592 {
2593  RtlFreeUnicodeString(&Names->FamilyNameW);
2594  RtlFreeUnicodeString(&Names->FaceNameW);
2595  RtlFreeUnicodeString(&Names->StyleNameW);
2596  RtlFreeUnicodeString(&Names->FullNameW);
2597 }
2598 
2599 /*************************************************************
2600  * IntGetOutlineTextMetrics
2601  *
2602  */
2603 INT FASTCALL
2605  UINT Size,
2606  OUTLINETEXTMETRICW *Otm)
2607 {
2608  TT_OS2 *pOS2;
2609  TT_HoriHeader *pHori;
2610  TT_Postscript *pPost;
2611  FT_Fixed XScale, YScale;
2612  FT_WinFNT_HeaderRec WinFNT;
2613  FT_Error Error;
2614  BYTE *pb;
2615  FONT_NAMES FontNames;
2616  PSHARED_FACE SharedFace = FontGDI->SharedFace;
2618  FT_Face Face = SharedFace->Face;
2619 
2621  {
2622  Cache = &SharedFace->EnglishUS;
2623  }
2624  else
2625  {
2626  Cache = &SharedFace->UserLanguage;
2627  }
2628 
2629  if (Size == 0 && Cache->OutlineRequiredSize > 0)
2630  {
2631  ASSERT(Otm == NULL);
2632  return Cache->OutlineRequiredSize;
2633  }
2634 
2635  IntInitFontNames(&FontNames, SharedFace);
2636  Cache->OutlineRequiredSize = FontNames.OtmSize;
2637 
2638  if (Size == 0)
2639  {
2640  ASSERT(Otm == NULL);
2641  IntFreeFontNames(&FontNames);
2642  return Cache->OutlineRequiredSize;
2643  }
2644 
2645  ASSERT(Otm != NULL);
2646 
2647  if (Size < Cache->OutlineRequiredSize)
2648  {
2649  DPRINT1("Size %u < OutlineRequiredSize %u\n", Size,
2650  Cache->OutlineRequiredSize);
2651  IntFreeFontNames(&FontNames);
2652  return 0; /* failure */
2653  }
2654 
2655  XScale = Face->size->metrics.x_scale;
2656  YScale = Face->size->metrics.y_scale;
2657 
2658  IntLockFreeType();
2659 
2660  pOS2 = FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
2661  pHori = FT_Get_Sfnt_Table(Face, FT_SFNT_HHEA);
2662  pPost = FT_Get_Sfnt_Table(Face, FT_SFNT_POST); /* We can live with this failing */
2663  Error = FT_Get_WinFNT_Header(Face, &WinFNT);
2664 
2665  if (pOS2 == NULL && Error)
2666  {
2668  DPRINT1("Can't find OS/2 table - not TT font?\n");
2669  IntFreeFontNames(&FontNames);
2670  return 0;
2671  }
2672 
2673  if (pHori == NULL && Error)
2674  {
2676  DPRINT1("Can't find HHEA table - not TT font?\n");
2677  IntFreeFontNames(&FontNames);
2678  return 0;
2679  }
2680 
2681  Otm->otmSize = Cache->OutlineRequiredSize;
2682 
2683  FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &WinFNT : 0);
2684 
2685  if (!pOS2)
2686  goto skip_os2;
2687 
2688  Otm->otmFiller = 0;
2690  Otm->otmfsSelection = pOS2->fsSelection;
2691  Otm->otmfsType = pOS2->fsType;
2692  Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2693  Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2694  Otm->otmItalicAngle = 0; /* POST table */
2695  Otm->otmEMSquare = Face->units_per_EM;
2696 
2697 #define SCALE_X(value) ((FT_MulFix((value), XScale) + 32) >> 6)
2698 #define SCALE_Y(value) ((FT_MulFix((value), YScale) + 32) >> 6)
2699 
2700  Otm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
2701  Otm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
2702  Otm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
2703  Otm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
2704  Otm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
2705  Otm->otmrcFontBox.left = SCALE_X(Face->bbox.xMin);
2706  Otm->otmrcFontBox.right = SCALE_X(Face->bbox.xMax);
2707  Otm->otmrcFontBox.top = SCALE_Y(Face->bbox.yMax);
2708  Otm->otmrcFontBox.bottom = SCALE_Y(Face->bbox.yMin);
2709  Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
2710  Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
2711  Otm->otmMacLineGap = Otm->otmLineGap;
2712  Otm->otmusMinimumPPEM = 0; /* TT Header */
2723 
2724  if (!pPost)
2725  {
2726  Otm->otmsUnderscoreSize = 0;
2727  Otm->otmsUnderscorePosition = 0;
2728  }
2729  else
2730  {
2733  }
2734 
2735 #undef SCALE_X
2736 #undef SCALE_Y
2737 
2738 skip_os2:
2740 
2741  pb = IntStoreFontNames(&FontNames, Otm);
2742  ASSERT(pb - (BYTE*)Otm == Cache->OutlineRequiredSize);
2743 
2744  IntFreeFontNames(&FontNames);
2745 
2746  return Cache->OutlineRequiredSize;
2747 }
2748 
2749 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
2750 static BYTE
2752 {
2753  /* FIXME: Add more and fix if wrong */
2754  switch (PRIMARYLANGID(LangID))
2755  {
2756  case LANG_CHINESE:
2757  switch (SUBLANGID(LangID))
2758  {
2760  return CHINESEBIG5_CHARSET;
2762  default:
2763  break;
2764  }
2765  return GB2312_CHARSET;
2766 
2767  case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
2768  case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
2769  return EASTEUROPE_CHARSET;
2770 
2771  case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
2772  case LANG_SERBIAN: case LANG_UKRAINIAN:
2773  return RUSSIAN_CHARSET;
2774 
2775  case LANG_ARABIC: return ARABIC_CHARSET;
2776  case LANG_GREEK: return GREEK_CHARSET;
2777  case LANG_HEBREW: return HEBREW_CHARSET;
2778  case LANG_JAPANESE: return SHIFTJIS_CHARSET;
2779  case LANG_KOREAN: return JOHAB_CHARSET;
2780  case LANG_TURKISH: return TURKISH_CHARSET;
2781  case LANG_THAI: return THAI_CHARSET;
2782  case LANG_LATVIAN: return BALTIC_CHARSET;
2783  case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
2784 
2785  case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
2786  case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
2787  case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
2788  case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
2789  case LANG_SWEDISH: default:
2790  return ANSI_CHARSET;
2791  }
2792 }
2793 
2794 static void
2796 {
2797  BYTE b, *pb = pvData;
2798  Size /= 2;
2799  while (Size-- > 0)
2800  {
2801  b = pb[0];
2802  pb[0] = pb[1];
2803  pb[1] = b;
2804  ++pb; ++pb;
2805  }
2806 }
2807 
2808 static NTSTATUS
2810  FT_UShort NameID, FT_UShort LangID)
2811 {
2812  FT_SfntName Name;
2813  INT i, Count, BestIndex, Score, BestScore;
2814  FT_Error Error;
2816  ANSI_STRING AnsiName;
2818  FT_Face Face = SharedFace->Face;
2819 
2820  RtlFreeUnicodeString(pNameW);
2821 
2822  /* select cache */
2823  if (PRIMARYLANGID(LangID) == LANG_ENGLISH)
2824  {
2825  Cache = &SharedFace->EnglishUS;
2826  }
2827  else
2828  {
2829  Cache = &SharedFace->UserLanguage;
2830  }
2831 
2832  /* use cache if available */
2833  if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer)
2834  {
2835  return DuplicateUnicodeString(&Cache->FontFamily, pNameW);
2836  }
2837  if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer)
2838  {
2839  return DuplicateUnicodeString(&Cache->FullName, pNameW);
2840  }
2841 
2842  BestIndex = -1;
2843  BestScore = 0;
2844 
2845  Count = FT_Get_Sfnt_Name_Count(Face);
2846  for (i = 0; i < Count; ++i)
2847  {
2848  Error = FT_Get_Sfnt_Name(Face, i, &Name);
2849  if (Error)
2850  {
2851  continue; /* failure */
2852  }
2853 
2854  if (Name.name_id != NameID)
2855  {
2856  continue; /* mismatched */
2857  }
2858 
2859  if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
2860  (Name.encoding_id != TT_MS_ID_UNICODE_CS &&
2861  Name.encoding_id != TT_MS_ID_SYMBOL_CS))
2862  {
2863  continue; /* not Microsoft Unicode name */
2864  }
2865 
2866  if (Name.string == NULL || Name.string_len == 0 ||
2867  (Name.string[0] == 0 && Name.string[1] == 0))
2868  {
2869  continue; /* invalid string */
2870  }
2871 
2872  if (Name.language_id == LangID)
2873  {
2874  Score = 30;
2875  BestIndex = i;
2876  break; /* best match */
2877  }
2878  else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID))
2879  {
2880  Score = 20;
2881  }
2882  else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH)
2883  {
2884  Score = 10;
2885  }
2886  else
2887  {
2888  Score = 0;
2889  }
2890 
2891  if (Score > BestScore)
2892  {
2893  BestScore = Score;
2894  BestIndex = i;
2895  }
2896  }
2897 
2898  if (BestIndex >= 0)
2899  {
2900  /* store the best name */
2901  Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
2902  if (!Error)
2903  {
2904  /* NOTE: Name.string is not null-terminated */
2905  UNICODE_STRING Tmp;
2906  Tmp.Buffer = (PWCH)Name.string;
2907  Tmp.Length = Tmp.MaximumLength = Name.string_len;
2908 
2909  pNameW->Length = 0;
2910  pNameW->MaximumLength = Name.string_len + sizeof(WCHAR);
2912 
2913  if (pNameW->Buffer)
2914  {
2915  Status = RtlAppendUnicodeStringToString(pNameW, &Tmp);
2916  if (Status == STATUS_SUCCESS)
2917  {
2918  /* Convert UTF-16 big endian to little endian */
2919  SwapEndian(pNameW->Buffer, pNameW->Length);
2920  }
2921  }
2922  else
2923  {
2925  }
2926  }
2927  }
2928 
2929  if (!NT_SUCCESS(Status))
2930  {
2931  /* defaulted */
2932  if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
2933  {
2934  RtlInitAnsiString(&AnsiName, Face->style_name);
2935  Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2936  }
2937  else
2938  {
2939  RtlInitAnsiString(&AnsiName, Face->family_name);
2940  Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2941  }
2942  }
2943 
2944  if (NT_SUCCESS(Status))
2945  {
2946  /* make cache */
2947  if (NameID == TT_NAME_ID_FONT_FAMILY)
2948  {
2950  IntLockFreeType();
2951  if (!Cache->FontFamily.Buffer)
2952  DuplicateUnicodeString(pNameW, &Cache->FontFamily);
2954  }
2955  else if (NameID == TT_NAME_ID_FULL_NAME)
2956  {
2958  IntLockFreeType();
2959  if (!Cache->FullName.Buffer)
2960  DuplicateUnicodeString(pNameW, &Cache->FullName);
2962  }
2963  }
2964 
2965  return Status;
2966 }
2967 
2968 static void FASTCALL
2970  LPCWSTR FullName, PFONTGDI FontGDI)
2971 {
2972  ANSI_STRING StyleA;
2973  UNICODE_STRING StyleW;
2974  TT_OS2 *pOS2;
2975  FONTSIGNATURE fs;
2976  CHARSETINFO CharSetInfo;
2977  unsigned i, Size;
2978  OUTLINETEXTMETRICW *Otm;
2979  LOGFONTW *Lf;
2980  TEXTMETRICW *TM;
2981  NEWTEXTMETRICW *Ntm;
2982  DWORD fs0;
2983  NTSTATUS status;
2984  PSHARED_FACE SharedFace = FontGDI->SharedFace;
2985  FT_Face Face = SharedFace->Face;
2986  UNICODE_STRING NameW;
2987 
2988  RtlInitUnicodeString(&NameW, NULL);
2989  RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
2990  Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2992  if (!Otm)
2993  {
2994  return;
2995  }
2996  Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2997  if (!Size)
2998  {
3000  return;
3001  }
3002 
3003  Lf = &Info->EnumLogFontEx.elfLogFont;
3004  TM = &Otm->otmTextMetrics;
3005 
3006  Lf->lfHeight = TM->tmHeight;
3007  Lf->lfWidth = TM->tmAveCharWidth;
3008  Lf->lfWeight = TM->tmWeight;
3009  Lf->lfItalic = TM->tmItalic;
3010  Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
3011  Lf->lfCharSet = TM->tmCharSet;
3014  Lf->lfQuality = PROOF_QUALITY;
3015 
3016  Ntm = &Info->NewTextMetricEx.ntmTm;
3017  Ntm->tmHeight = TM->tmHeight;
3018  Ntm->tmAscent = TM->tmAscent;
3019  Ntm->tmDescent = TM->tmDescent;
3022  Ntm->tmAveCharWidth = TM->tmAveCharWidth;
3023  Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
3024  Ntm->tmWeight = TM->tmWeight;
3025  Ntm->tmOverhang = TM->tmOverhang;
3028  Ntm->tmFirstChar = TM->tmFirstChar;
3029  Ntm->tmLastChar = TM->tmLastChar;
3030  Ntm->tmDefaultChar = TM->tmDefaultChar;
3031  Ntm->tmBreakChar = TM->tmBreakChar;
3032  Ntm->tmItalic = TM->tmItalic;
3033  Ntm->tmUnderlined = TM->tmUnderlined;
3034  Ntm->tmStruckOut = TM->tmStruckOut;
3036  Ntm->tmCharSet = TM->tmCharSet;
3037  Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
3038 
3039  if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
3040 
3041  if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
3042 
3043  Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
3044  ? TRUETYPE_FONTTYPE : 0);
3045 
3046  if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
3047  Info->FontType |= RASTER_FONTTYPE;
3048 
3049 
3050  /* face name */
3051  if (!FaceName)
3052  FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
3053 
3054  RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
3055 
3056  /* full name */
3057  if (!FullName)
3058  FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName);
3059 
3060  RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
3061  sizeof(Info->EnumLogFontEx.elfFullName),
3062  FullName);
3063 
3064  RtlInitAnsiString(&StyleA, Face->style_name);
3065  StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
3066  StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
3067  status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
3068  if (!NT_SUCCESS(status))
3069  {
3071  return;
3072  }
3073  Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
3074 
3075  IntLockFreeType();
3076  pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3077 
3078  if (!pOS2)
3079  {
3082  return;
3083  }
3084 
3085  Ntm->ntmSizeEM = Otm->otmEMSquare;
3086  Ntm->ntmCellHeight = (FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent;
3087  Ntm->ntmAvgWidth = 0;
3088 
3090 
3091  fs.fsCsb[0] = pOS2->ulCodePageRange1;
3092  fs.fsCsb[1] = pOS2->ulCodePageRange2;
3093  fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3094  fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3095  fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3096  fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3097 
3098  if (0 == pOS2->version)
3099  {
3100  FT_UInt Dummy;
3101 
3102  if (FT_Get_First_Char(Face, &Dummy) < 0x100)
3103  fs.fsCsb[0] |= FS_LATIN1;
3104  else
3105  fs.fsCsb[0] |= FS_SYMBOL;
3106  }
3108 
3109  if (fs.fsCsb[0] == 0)
3110  {
3111  /* Let's see if we can find any interesting cmaps */
3112  for (i = 0; i < (UINT)Face->num_charmaps; i++)
3113  {
3114  switch (Face->charmaps[i]->encoding)
3115  {
3116  case FT_ENCODING_UNICODE:
3117  case FT_ENCODING_APPLE_ROMAN:
3118  fs.fsCsb[0] |= FS_LATIN1;
3119  break;
3120  case FT_ENCODING_MS_SYMBOL:
3121  fs.fsCsb[0] |= FS_SYMBOL;
3122  break;
3123  default:
3124  break;
3125  }
3126  }
3127  }
3128 
3129  for (i = 0; i < MAXTCIINDEX; i++)
3130  {
3131  fs0 = 1L << i;
3132  if (fs.fsCsb[0] & fs0)
3133  {
3134  if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
3135  {
3136  CharSetInfo.ciCharset = DEFAULT_CHARSET;
3137  }
3138  if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
3139  {
3140  if (g_ElfScripts[i])
3141  wcscpy(Info->EnumLogFontEx.elfScript, g_ElfScripts[i]);
3142  else
3143  {
3144  DPRINT1("Unknown elfscript for bit %u\n", i);
3145  }
3146  }
3147  }
3148  }
3149  Info->NewTextMetricEx.ntmFontSig = fs;
3150 }
3151 
3152 static BOOLEAN FASTCALL
3155  LPCWSTR NominalName,
3156  LONG *pCount,
3157  LONG MaxCount,
3158  PLIST_ENTRY Head)
3159 {
3161  PFONT_ENTRY CurrentEntry;
3162  FONTGDI *FontGDI;
3163  FONTFAMILYINFO InfoEntry;
3164  LONG Count = *pCount;
3165 
3166  for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
3167  {
3168  CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
3169  FontGDI = CurrentEntry->Font;
3170  ASSERT(FontGDI);
3171 
3172  if (LogFont->lfCharSet != DEFAULT_CHARSET &&
3173  LogFont->lfCharSet != FontGDI->CharSet)
3174  {
3175  continue; /* charset mismatch */
3176  }
3177 
3178  /* get one info entry */
3179  FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
3180 
3181  if (LogFont->lfFaceName[0] != UNICODE_NULL)
3182  {
3183  /* check name */
3184  if (_wcsnicmp(LogFont->lfFaceName,
3186  RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0 &&
3187  _wcsnicmp(LogFont->lfFaceName,
3188  InfoEntry.EnumLogFontEx.elfFullName,
3189  RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0)
3190  {
3191  continue;
3192  }
3193  }
3194 
3195  if (NominalName)
3196  {
3197  /* store the nominal name */
3199  sizeof(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName),
3200  NominalName);
3201  }
3202 
3203  /* store one entry to Info */
3204  if (0 <= Count && Count < MaxCount)
3205  {
3206  RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
3207  }
3208  Count++;
3209  }
3210 
3211  *pCount = Count;
3212 
3213  return TRUE;
3214 }
3215 
3216 static BOOLEAN FASTCALL
3219  LONG *pCount,
3220  LONG MaxCount)
3221 {
3222  PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead;
3223  PFONTSUBST_ENTRY pCurrentEntry;
3224  PUNICODE_STRING pFromW, pToW;
3225  LOGFONTW lf = *LogFont;
3227 
3228  for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
3229  {
3230  pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
3231 
3232  pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
3233  if (LogFont->lfFaceName[0] != UNICODE_NULL)
3234  {
3235  /* check name */
3236  if (_wcsicmp(LogFont->lfFaceName, pFromW->Buffer) != 0)
3237  continue; /* mismatch */
3238  }
3239 
3240  pToW = &pCurrentEntry->FontNames[FONTSUBST_TO];
3241  if (RtlEqualUnicodeString(pFromW, pToW, TRUE) &&
3242  pCurrentEntry->CharSets[FONTSUBST_FROM] ==
3243  pCurrentEntry->CharSets[FONTSUBST_TO])
3244  {
3245  /* identical mapping */
3246  continue;
3247  }
3248 
3249  /* substitute and get the real name */
3250  IntUnicodeStringToBuffer(lf.lfFaceName, sizeof(lf.lfFaceName), pFromW);
3251  SubstituteFontRecurse(&lf);
3252  if (LogFont->lfCharSet != DEFAULT_CHARSET && LogFont->lfCharSet != lf.lfCharSet)
3253  continue;
3254 
3255  /* search in global fonts */
3257  GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount, &g_FontListHead);
3259 
3260  /* search in private fonts */
3261  IntLockProcessPrivateFonts(Win32Process);
3262  GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount,
3263  &Win32Process->PrivateFontListHead);
3264  IntUnLockProcessPrivateFonts(Win32Process);
3265 
3266  if (LogFont->lfFaceName[0] != UNICODE_NULL)
3267  {
3268  /* it's already matched to the exact name and charset if the name
3269  was specified at here, then so don't scan more for another name */
3270  break;
3271  }
3272  }
3273 
3274  return TRUE;
3275 }
3276 
3277 BOOL
3278 FASTCALL
3280 {
3281  if ( lprs )
3282  {
3283  lprs->nSize = sizeof(RASTERIZER_STATUS);
3284  lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
3285  lprs->nLanguageID = gusLanguageID;
3286  return TRUE;
3287  }
3289  return FALSE;
3290 }
3291 
3292 static
3293 BOOL
3295  PMATRIX pmx1,
3296  PMATRIX pmx2)
3297 {
3298  return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
3299  FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
3300  FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
3301  FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
3302 }
3303 
3306  FT_Face Face,
3307  INT GlyphIndex,
3308  INT Height,
3309  FT_Render_Mode RenderMode,
3310  PMATRIX pmx)
3311 {
3312  PLIST_ENTRY CurrentEntry;
3313  PFONT_CACHE_ENTRY FontEntry;
3314 
3316 
3317  for (CurrentEntry = g_FontCacheListHead.Flink;
3318  CurrentEntry != &g_FontCacheListHead;
3319  CurrentEntry = CurrentEntry->Flink)
3320  {
3321  FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
3322  if ((FontEntry->Face == Face) &&
3323  (FontEntry->GlyphIndex == GlyphIndex) &&
3324  (FontEntry->Height == Height) &&
3325  (FontEntry->RenderMode == RenderMode) &&
3326  (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
3327  break;
3328  }
3329 
3330  if (CurrentEntry == &g_FontCacheListHead)
3331  {
3332  return NULL;
3333  }
3334 
3335  RemoveEntryList(CurrentEntry);
3336  InsertHeadList(&g_FontCacheListHead, CurrentEntry);
3337  return FontEntry->BitmapGlyph;
3338 }
3339 
3340 /* no cache */
3343  FT_Face Face,
3344  FT_GlyphSlot GlyphSlot,
3345  FT_Render_Mode RenderMode)
3346 {
3347  FT_Glyph Glyph;
3348  INT error;
3349  FT_Bitmap AlignedBitmap;
3350  FT_BitmapGlyph BitmapGlyph;
3351 
3352  error = FT_Get_Glyph(GlyphSlot, &Glyph);
3353  if (error)
3354  {
3355  DPRINT1("Failure getting glyph.\n");
3356  return NULL;
3357  }
3358 
3359  error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
3360  if (error)
3361  {
3362  FT_Done_Glyph(Glyph);
3363  DPRINT1("Failure rendering glyph.\n");
3364  return NULL;
3365  }
3366 
3367  BitmapGlyph = (FT_BitmapGlyph)Glyph;
3368  FT_Bitmap_New(&AlignedBitmap);
3369  if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
3370  {
3371  DPRINT1("Conversion failed\n");
3372  FT_Done_Glyph((FT_Glyph)BitmapGlyph);
3373  return NULL;
3374  }
3375 
3376  FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
3377  BitmapGlyph->bitmap = AlignedBitmap;
3378 
3379  return BitmapGlyph;
3380 }
3381 
3384  FT_Face Face,
3385  INT GlyphIndex,
3386  INT Height,
3387  PMATRIX pmx,
3388  FT_GlyphSlot GlyphSlot,
3389  FT_Render_Mode RenderMode)
3390 {
3391  FT_Glyph GlyphCopy;
3392  INT error;
3393  PFONT_CACHE_ENTRY NewEntry;
3394  FT_Bitmap AlignedBitmap;
3395  FT_BitmapGlyph BitmapGlyph;
3396 
3398 
3399  error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
3400  if (error)
3401  {
3402  DPRINT1("Failure caching glyph.\n");
3403  return NULL;
3404  };
3405 
3406  error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
3407  if (error)
3408  {
3409  FT_Done_Glyph(GlyphCopy);
3410  DPRINT1("Failure rendering glyph.\n");
3411  return NULL;
3412  };
3413 
3415  if (!NewEntry)
3416  {
3417  DPRINT1("Alloc failure caching glyph.\n");
3418  FT_Done_Glyph(GlyphCopy);
3419  return NULL;
3420  }
3421 
3422  BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
3423  FT_Bitmap_New(&AlignedBitmap);
3424  if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
3425  {
3426  DPRINT1("Conversion failed\n");
3427  ExFreePoolWithTag(NewEntry, TAG_FONT);
3428  FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
3429  FT_Done_Glyph((FT_Glyph)BitmapGlyph);
3430  return NULL;
3431  }
3432 
3433  FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
3434  BitmapGlyph->bitmap = AlignedBitmap;
3435 
3436  NewEntry->GlyphIndex = GlyphIndex;
3437  NewEntry->Face = Face;
3438  NewEntry->BitmapGlyph = BitmapGlyph;
3439  NewEntry->Height = Height;
3440  NewEntry->RenderMode = RenderMode;
3441  NewEntry->mxWorldToDevice = *pmx;
3442 
3445  {
3447  RemoveCachedEntry(NewEntry);
3448  }
3449 
3450  return BitmapGlyph;
3451 }
3452 
3453 
3454 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3455 {
3456  TTPOLYGONHEADER *pph;
3457  TTPOLYCURVE *ppc;
3458  int needed = 0, point = 0, contour, first_pt;
3459  unsigned int pph_start, cpfx;
3460  DWORD type;
3461 
3462  for (contour = 0; contour < outline->n_contours; contour++)
3463  {
3464  /* Ignore contours containing one point */
3465  if (point == outline->contours[contour])
3466  {
3467  point++;
3468  continue;
3469  }
3470 
3471  pph_start = needed;
3472  pph = (TTPOLYGONHEADER *)(buf + needed);
3473  first_pt = point;
3474  if (buf)
3475  {
3476  pph->dwType = TT_POLYGON_TYPE;
3477  FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3478  }
3479  needed += sizeof(*pph);
3480  point++;
3481  while (point <= outline->contours[contour])
3482  {
3483  ppc = (TTPOLYCURVE *)(buf + needed);
3484  type = outline->tags[point] & FT_Curve_Tag_On ?
3486  cpfx = 0;
3487  do
3488  {
3489  if (buf)
3490  FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3491  cpfx++;
3492  point++;
3493  } while (point <= outline->contours[contour] &&
3494  (outline->tags[point] & FT_Curve_Tag_On) ==
3495  (outline->tags[point-1] & FT_Curve_Tag_On));
3496  /* At the end of a contour Windows adds the start point, but
3497  only for Beziers */
3498  if (point > outline->contours[contour] &&
3499  !(outline->tags[point-1] & FT_Curve_Tag_On))
3500  {
3501  if (buf)
3502  FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3503  cpfx++;
3504  }
3505  else if (point <= outline->contours[contour] &&
3506  outline->tags[point] & FT_Curve_Tag_On)
3507  {
3508  /* add closing pt for bezier */
3509  if (buf)
3510  FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3511  cpfx++;
3512  point++;
3513  }
3514  if (buf)
3515  {
3516  ppc->wType = type;
3517  ppc->cpfx = cpfx;
3518  }
3519  needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3520  }
3521  if (buf)
3522  pph->cb = needed - pph_start;
3523  }
3524  return needed;
3525 }
3526 
3527 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3528 {
3529  /* Convert the quadratic Beziers to cubic Beziers.
3530  The parametric eqn for a cubic Bezier is, from PLRM:
3531  r(t) = at^3 + bt^2 + ct + r0
3532  with the control points:
3533  r1 = r0 + c/3
3534  r2 = r1 + (c + b)/3
3535  r3 = r0 + c + b + a
3536 
3537  A quadratic Bezier has the form:
3538  p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3539 
3540  So equating powers of t leads to:
3541  r1 = 2/3 p1 + 1/3 p0
3542  r2 = 2/3 p1 + 1/3 p2
3543  and of course r0 = p0, r3 = p2
3544  */
3545  int contour, point = 0, first_pt;
3546  TTPOLYGONHEADER *pph;
3547  TTPOLYCURVE *ppc;
3548  DWORD pph_start, cpfx, type;
3549  FT_Vector cubic_control[4];
3550  unsigned int needed = 0;
3551 
3552  for (contour = 0; contour < outline->n_contours; contour++)
3553  {
3554  pph_start = needed;
3555  pph = (TTPOLYGONHEADER *)(buf + needed);
3556  first_pt = point;
3557  if (buf)
3558  {
3559  pph->dwType = TT_POLYGON_TYPE;
3560  FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3561  }
3562  needed += sizeof(*pph);
3563  point++;
3564  while (point <= outline->contours[contour])
3565  {
3566  ppc = (TTPOLYCURVE *)(buf + needed);
3567  type = outline->tags[point] & FT_Curve_Tag_On ?
3569  cpfx = 0;
3570  do
3571  {
3572  if (type == TT_PRIM_LINE)
3573  {
3574  if (buf)
3575  FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3576  cpfx++;
3577  point++;
3578  }
3579  else
3580  {
3581  /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3582  so cpfx = 3n */
3583 
3584  /* FIXME: Possible optimization in endpoint calculation
3585  if there are two consecutive curves */
3586  cubic_control[0] = outline->points[point-1];
3587  if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3588  {
3589  cubic_control[0].x += outline->points[point].x + 1;
3590  cubic_control[0].y += outline->points[point].y + 1;
3591  cubic_control[0].x >>= 1;
3592  cubic_control[0].y >>= 1;
3593  }
3594  if (point+1 > outline->contours[contour])
3595  cubic_control[3] = outline->points[first_pt];
3596  else
3597  {
3598  cubic_control[3] = outline->points[point+1];
3599  if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3600  {
3601  cubic_control[3].x += outline->points[point].x + 1;
3602  cubic_control[3].y += outline->points[point].y + 1;
3603  cubic_control[3].x >>= 1;
3604  cubic_control[3].y >>= 1;
3605  }
3606  }
3607  /* r1 = 1/3 p0 + 2/3 p1
3608  r2 = 1/3 p2 + 2/3 p1 */
3609  cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3610  cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3611  cubic_control[2] = cubic_control[1];
3612  cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3613  cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3614  cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3615  cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3616  if (buf)
3617  {
3618  FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3619  FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3620  FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3621  }
3622  cpfx += 3;
3623  point++;
3624  }
3625  } while (point <= outline->contours[contour] &&
3626  (outline->tags[point] & FT_Curve_Tag_On) ==
3627  (outline->tags[point-1] & FT_Curve_Tag_On));
3628  /* At the end of a contour Windows adds the start point,
3629  but only for Beziers and we've already done that.
3630  */
3631  if (point <= outline->contours[contour] &&
3632  outline->tags[point] & FT_Curve_Tag_On)
3633  {
3634  /* This is the closing pt of a bezier, but we've already
3635  added it, so just inc point and carry on */
3636  point++;
3637  }
3638  if (buf)
3639  {
3640  ppc->wType = type;
3641  ppc->cpfx = cpfx;
3642  }
3643  needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3644  }
3645  if (buf)
3646  pph->cb = needed - pph_start;
3647  }
3648  return needed;
3649 }
3650 
3651 static FT_Error
3652 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
3653 {
3654  FT_Error error;
3655  FT_Size_RequestRec req;
3656  FT_Face face = FontGDI->SharedFace->Face;
3657  TT_OS2 *pOS2;
3658  TT_HoriHeader *pHori;
3659  FT_WinFNT_HeaderRec WinFNT;
3660  LONG Ascent, Descent, Sum, EmHeight64;
3661 
3662  lfWidth = abs(lfWidth);
3663  if (lfHeight == 0)
3664  {
3665  if (lfWidth == 0)
3666  {
3667  DPRINT("lfHeight and lfWidth are zero.\n");
3668  lfHeight = -16;
3669  }
3670  else
3671  {
3672  lfHeight = lfWidth;
3673  }
3674  }
3675 
3676  if (lfHeight == -1)
3677  lfHeight = -2;
3678 
3682 
3683  if (!pOS2 || !pHori)
3684  {
3685  error = FT_Get_WinFNT_Header(face, &WinFNT);
3686  if (error)
3687  {
3688  DPRINT1("%s: Failed to request font size.\n", face->family_name);
3689  ASSERT(FALSE);
3690  return error;
3691  }
3692 
3693  FontGDI->tmHeight = WinFNT.pixel_height;
3694  FontGDI->tmAscent = WinFNT.ascent;
3695  FontGDI->tmDescent = FontGDI->tmHeight - FontGDI->tmAscent;
3696  FontGDI->tmInternalLeading = WinFNT.internal_leading;
3697  FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3698  FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3699  FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3700  FontGDI->Magic = FONTGDI_MAGIC;
3701  return 0;
3702  }
3703 
3704  /*
3705  * NOTE: We cast TT_OS2.usWinAscent and TT_OS2.usWinDescent to signed FT_Short.
3706  * Why? See: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswindescent
3707  *
3708  * > usWinDescent is "usually" a positive value ...
3709  *
3710  * We can read it as "not always". See CORE-14994.
3711  * See also: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fsselection
3712  */
3713 #define FM_SEL_USE_TYPO_METRICS 0x80
3714  if (lfHeight > 0)
3715  {
3716  /* case (A): lfHeight is positive */
3717  Sum = (FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent;
3718  if (Sum == 0 || (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS))
3719  {
3720  Ascent = pHori->Ascender;
3721  Descent = -pHori->Descender;
3722  Sum = Ascent + Descent;
3723  }
3724  else
3725  {
3726  Ascent = (FT_Short)pOS2->usWinAscent;
3727  Descent = (FT_Short)pOS2->usWinDescent;
3728  }
3729 
3730  FontGDI->tmAscent = FT_MulDiv(lfHeight, Ascent, Sum);
3731  FontGDI->tmDescent = FT_MulDiv(lfHeight, Descent, Sum);
3732  FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3733  FontGDI->tmInternalLeading = FontGDI->tmHeight - FT_MulDiv(lfHeight, face->units_per_EM, Sum);
3734  }
3735  else if (lfHeight < 0)
3736  {
3737  /* case (B): lfHeight is negative */
3739  {
3740  FontGDI->tmAscent = FT_MulDiv(-lfHeight, pHori->Ascender, face->units_per_EM);
3741  FontGDI->tmDescent = FT_MulDiv(-lfHeight, -pHori->Descender, face->units_per_EM);
3742  }
3743  else
3744  {
3745  FontGDI->tmAscent = FT_MulDiv(-lfHeight, (FT_Short)pOS2->usWinAscent, face->units_per_EM);
3746  FontGDI->tmDescent = FT_MulDiv(-lfHeight, (FT_Short)pOS2->usWinDescent, face->units_per_EM);
3747  }
3748  FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3749  FontGDI->tmInternalLeading = FontGDI->tmHeight + lfHeight;
3750  }
3751 #undef FM_SEL_USE_TYPO_METRICS
3752 
3753  FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3754  FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3755  FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3756  FontGDI->Magic = FONTGDI_MAGIC;
3757 
3758  EmHeight64 = (FontGDI->EmHeight << 6);
3759 
3761  req.width = 0;
3762  req.height = EmHeight64;
3763  req.horiResolution = 0;
3764  req.vertResolution = 0;
3765  return FT_Request_Size(face, &req);
3766 }
3767 
3768 BOOL
3769 FASTCALL
3771  PTEXTOBJ TextObj,
3772  PFONTGDI FontGDI,
3773  BOOL bDoLock)
3774 {
3775  FT_Face face;
3776  INT error, n;
3777  FT_CharMap charmap, found;
3778  LOGFONTW *plf;
3779 
3780  if (bDoLock)
3781  IntLockFreeType();
3782 
3783  face = FontGDI->SharedFace->Face;
3784  if (face->charmap == NULL)
3785  {
3786  DPRINT("WARNING: No charmap selected!\n");
3787  DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3788 
3789  found = NULL;
3790  for (n = 0; n < face->num_charmaps; n++)
3791  {
3792  charmap = face->charmaps[n];
3793  if (charmap->encoding == FT_ENCODING_UNICODE)
3794  {
3795  found = charmap;
3796  break;
3797  }
3798  }
3799  if (!found)
3800  {
3801  for (n = 0; n < face->num_charmaps; n++)
3802  {
3803  charmap = face->charmaps[n];
3804  if (charmap->platform_id == TT_PLATFORM_APPLE_UNICODE)
3805  {
3806  found = charmap;
3807  break;
3808  }
3809  }
3810  }
3811  if (!found)
3812  {
3813  for (n = 0; n < face->num_charmaps; n++)
3814  {
3815  charmap = face->charmaps[n];
3816  if (charmap->encoding == FT_ENCODING_MS_SYMBOL)
3817  {
3818  found = charmap;
3819  break;
3820  }
3821  }
3822  }
3823  if (!found && face->num_charmaps > 0)
3824  {
3825  found = face->charmaps[0];
3826  }
3827  if (!found)
3828  {
3829  DPRINT1("WARNING: Could not find desired charmap!\n");
3830  }
3831  else
3832  {
3833  DPRINT("Found charmap encoding: %i\n", found->encoding);
3834  error = FT_Set_Charmap(face, found);
3835  if (error)
3836  {
3837  DPRINT1("WARNING: Could not set the charmap!\n");
3838  }
3839  }
3840  }
3841 
3842  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3843 
3844  error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
3845 
3846  if (bDoLock)
3848 
3849  if (error)
3850  {
3851  DPRINT1("Error in setting pixel sizes: %d\n", error);
3852  return FALSE;
3853  }
3854 
3855  return TRUE;
3856 }
3857 
3858 static inline FT_UInt FASTCALL
3860 {
3861  FT_UInt ret;
3862 
3863  if (glyph < 0x100) glyph += 0xf000;
3864  /* there are a number of old pre-Unicode "broken" TTFs, which
3865  do have symbols at U+00XX instead of U+f0XX */
3866  if (!(ret = FT_Get_Char_Index(ft_face, glyph)))
3867  ret = FT_Get_Char_Index(ft_face, glyph - 0xf000);
3868 
3869  return ret;
3870 }
3871 
3872 static inline FT_UInt FASTCALL
3874 {
3875  FT_UInt ret;
3876 
3877  if (face_has_symbol_charmap(ft_face))
3878  {
3879  ret = get_glyph_index_symbol(ft_face, glyph);
3880  if (ret != 0)
3881  return ret;
3882  }
3883 
3884  return FT_Get_Char_Index(ft_face, glyph);
3885 }
3886 
3887 static inline FT_UInt FASTCALL
3889 {
3890  FT_UInt glyph_index;
3891  if (flags & indexed_flag)
3892  {
3893  glyph_index = code;
3894  }
3895  else
3896  {
3897  glyph_index = get_glyph_index(face, code);
3898  }
3899  return glyph_index;
3900 }
3901 
3902 /*
3903  * Based on WineEngGetGlyphOutline
3904  *
3905  */
3906 ULONG
3907 FASTCALL
3909  PDC dc,
3910  WCHAR wch,
3911  UINT iFormat,
3912  LPGLYPHMETRICS pgm,
3913  ULONG cjBuf,
3914  PVOID pvBuf,
3915  LPMAT2 pmat2,
3916  BOOL bIgnoreRotation)
3917 {
3918  PDC_ATTR pdcattr;
3919  PTEXTOBJ TextObj;
3920  PFONTGDI FontGDI;
3921  HFONT hFont = 0;
3922  GLYPHMETRICS gm;
3923  ULONG Size;
3924  FT_Face ft_face;
3925  FT_UInt glyph_index;
3926  DWORD width, height, pitch, needed = 0;
3927  FT_Bitmap ft_bitmap;
3928  FT_Error error;
3929  INT left, right, top = 0, bottom = 0;
3931  FLOATOBJ eM11, widthRatio, eTemp;
3932  FT_Matrix transMat = identityMat;
3933  BOOL needsTransform = FALSE;
3934  INT orientation;
3935  LONG aveWidth;
3936  INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3937  OUTLINETEXTMETRICW *potm;
3938  XFORMOBJ xo;
3939  XFORML xform;
3940  LOGFONTW *plf;
3941 
3942  DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3943  cjBuf, pvBuf, pmat2);
3944 
3945  pdcattr = dc->pdcattr;
3946 
3947  XFORMOBJ_vInit(&xo, &dc->pdcattr->mxWorldToDevice);
3948  XFORMOBJ_iGetXform(&xo, &xform);
3949  FLOATOBJ_SetFloat(&eM11, xform.eM11);
3950 
3951  hFont = pdcattr->hlfntNew;
3952  TextObj = RealizeFontInit(hFont);
3953 
3954  if (!TextObj)
3955  {
3957  return GDI_ERROR;
3958  }
3959  FontGDI = ObjToGDI(TextObj->Font, FONT);
3960  ft_face = FontGDI->SharedFace->Face;
3961 
3962  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3963  aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3964  orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3965 
3966  Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3968  if (!potm)
3969  {
3971  TEXTOBJ_UnlockText(TextObj);
3972  return GDI_ERROR;
3973  }
3974  Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
3975  if (!Size)
3976  {
3977  /* FIXME: last error? */
3979  TEXTOBJ_UnlockText(TextObj);
3980  return GDI_ERROR;
3981  }
3982 
3983  IntLockFreeType();
3984  TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3986 
3987  TEXTOBJ_UnlockText(TextObj);
3988 
3989  glyph_index = get_glyph_index_flagged(ft_face, wch, GGO_GLYPH_INDEX, iFormat);
3991 
3992  if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3993  load_flags |= FT_LOAD_NO_BITMAP;
3994 
3995  if (iFormat & GGO_UNHINTED)
3996  {
3997  load_flags |= FT_LOAD_NO_HINTING;
3998  iFormat &= ~GGO_UNHINTED;
3999  }
4000 
4001  error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
4002  if (error)
4003  {
4004  DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
4006  if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
4007  return GDI_ERROR;
4008  }
4010 
4011  FLOATOBJ_Set1(&widthRatio);
4012  if (aveWidth && potm)
4013  {
4014  // widthRatio = aveWidth * eM11 / potm->otmTextMetrics.tmAveCharWidth
4015  FLOATOBJ_SetLong(&widthRatio, aveWidth);
4016  FLOATOBJ_Mul(&widthRatio, &eM11);
4017  FLOATOBJ_DivLong(&widthRatio, potm->otmTextMetrics.tmAveCharWidth);
4018  }
4019 
4020  //left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
4021  FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiBearingX);
4022  FLOATOBJ_Mul(&eTemp, &widthRatio);
4023  left = FLOATOBJ_GetLong(&eTemp) & -64;
4024 
4025  //right = (INT)((ft_face->glyph->metrics.horiBearingX +
4026  // ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
4027  FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiBearingX * ft_face->glyph->metrics.width);
4028  FLOATOBJ_Mul(&eTemp, &widthRatio);
4029  FLOATOBJ_AddLong(&eTemp, 63);
4030  right = FLOATOBJ_GetLong(&eTemp) & -64;
4031 
4032  //adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
4033  FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiAdvance);
4034  FLOATOBJ_Mul(&eTemp, &widthRatio);
4035  FLOATOBJ_AddLong(&eTemp, 63);
4036  adv = FLOATOBJ_GetLong(&eTemp) >> 6;
4037 
4038  lsb = left >> 6;
4039  bbx = (right - left) >> 6;
4040 
4041  DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
4042 
4043  IntLockFreeType();
4044 
4045  /* Width scaling transform */
4046  if (!FLOATOBJ_Equal1(&widthRatio))
4047  {
4048  FT_Matrix scaleMat;
4049 
4050  eTemp = widthRatio;
4051  FLOATOBJ_MulLong(&eTemp, 1 << 16);
4052 
4053  scaleMat.xx = FLOATOBJ_GetLong(&eTemp);
4054  scaleMat.xy = 0;
4055  scaleMat.yx = 0;
4056  scaleMat.yy = INT_TO_FIXED(1);
4057  FT_Matrix_Multiply(&scaleMat, &transMat);
4058  needsTransform = TRUE;
4059  }
4060 
4061  /* World transform */
4062  {
4063  FT_Matrix ftmatrix;
4065 
4066  /* Create a freetype matrix, by converting to 16.16 fixpoint format */
4067  FtMatrixFromMx(&ftmatrix, pmx);
4068 
4069  if (memcmp(&ftmatrix, &identityMat, sizeof(identityMat)) != 0)
4070  {
4071  FT_Matrix_Multiply(&ftmatrix, &transMat);
4072  needsTransform = TRUE;
4073  }
4074  }
4075 
4076  /* Rotation transform */
4077  if (orientation)
4078  {
4079  FT_Matrix rotationMat;
4080  DPRINT("Rotation Trans!\n");
4081  IntEscapeMatrix(&rotationMat, orientation);
4082  FT_Matrix_Multiply(&rotationMat, &transMat);
4083  needsTransform = TRUE;
4084  }
4085 
4086  /* Extra transformation specified by caller */
4087  if (pmat2)
4088  {
4089  FT_Matrix extraMat;
4090  DPRINT("MAT2 Matrix Trans!\n");
4091  extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
4092  extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
4093  extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
4094  extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
4095  FT_Matrix_Multiply(&extraMat, &transMat);
4096  needsTransform = TRUE;
4097  }
4098 
4099  if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
4100 
4101  if (!needsTransform)
4102  {
4103  DPRINT("No Need to be Transformed!\n");
4104  top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4105  bottom = (ft_face->glyph->metrics.horiBearingY -
4106  ft_face->glyph->metrics.height) & -64;
4107  gm.gmCellIncX = adv;
4108  gm.gmCellIncY = 0;
4109  }
4110  else
4111  {
4112  INT xc, yc;
4113  FT_Vector vec;
4114  for (xc = 0; xc < 2; xc++)
4115  {
4116  for (yc = 0; yc < 2; yc++)
4117  {
4118  vec.x = (ft_face->glyph->metrics.horiBearingX +
4119  xc * ft_face->glyph->metrics.width);
4120  vec.y = ft_face->glyph->metrics.horiBearingY -
4121  yc * ft_face->glyph->metrics.height;
4122  DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
4123  FT_Vector_Transform(&vec, &transMat);
4124  if (xc == 0 && yc == 0)
4125  {
4126  left = right = vec.x;
4127  top = bottom = vec.y;
4128  }
4129  else
4130  {
4131  if (vec.x < left) left = vec.x;
4132  else if (vec.x > right) right = vec.x;
4133  if (vec.y < bottom) bottom = vec.y;
4134  else if (vec.y > top) top = vec.y;
4135  }
4136  }
4137  }
4138  left = left & -64;
4139  right = (right + 63) & -64;
4140  bottom = bottom & -64;
4141  top = (top + 63) & -64;
4142 
4143  DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4144  vec.x = ft_face->glyph->metrics.horiAdvance;
4145  vec.y = 0;
4146  FT_Vector_Transform(&vec, &transMat);
4147  gm.gmCellIncX = (vec.x+63) >> 6;
4148  gm.gmCellIncY = -((vec.y+63) >> 6);
4149  }
4150  gm.gmBlackBoxX = (right - left) >> 6;
4151  gm.gmBlackBoxY = (top - bottom) >> 6;
4152  gm.gmptGlyphOrigin.x = left >> 6;
4153  gm.gmptGlyphOrigin.y = top >> 6;
4154 
4155  DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
4156  gm.gmCellIncX, gm.gmCellIncY,
4157  gm.gmBlackBoxX, gm.gmBlackBoxY,
4159 
4161 
4162 
4163  if (iFormat == GGO_METRICS)
4164  {
4165  DPRINT("GGO_METRICS Exit!\n");
4166  *pgm = gm;
4167  return 1; /* FIXME */
4168  }
4169 
4170  if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
4171  {
4172  DPRINT1("Loaded a bitmap\n");
4173  return GDI_ERROR;
4174  }
4175 
4176  switch (iFormat)
4177  {
4178  case GGO_BITMAP:
4179  {
4180  width = gm.gmBlackBoxX;
4181  height = gm.gmBlackBoxY;
4182  pitch = ((width + 31) >> 5) << 2;
4183  needed = pitch * height;
4184 
4185  if (!pvBuf || !cjBuf) break;
4186  if (!needed) return GDI_ERROR; /* empty glyph */
4187  if (needed > cjBuf)
4188  return GDI_ERROR;
4189 
4190  switch (ft_face->glyph->format)
4191  {
4193  {
4194  BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
4195  INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
4196  INT h = min( height, ft_face->glyph->bitmap.rows );
4197  while (h--)
4198  {
4199  RtlCopyMemory(dst, src, w);
4200  src += ft_face->glyph->bitmap.pitch;
4201  dst += pitch;
4202  }
4203  break;
4204  }
4205 
4207  {
4208  ft_bitmap.width = width;
4209  ft_bitmap.rows = height;
4210  ft_bitmap.pitch = pitch;
4211  ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
4212  ft_bitmap.buffer = pvBuf;
4213 
4214  IntLockFreeType();
4215  if (needsTransform)
4216  {
4217  FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4218  }
4219  FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4220  /* Note: FreeType will only set 'black' bits for us. */
4221  RtlZeroMemory(pvBuf, needed);
4222  FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
4224  break;
4225  }
4226 
4227  default:
4228  DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
4229  return GDI_ERROR;
4230  }
4231 
4232  break;
4233  }
4234 
4235  case GGO_GRAY2_BITMAP:
4236  case GGO_GRAY4_BITMAP:
4237  case GGO_GRAY8_BITMAP:
4238  {
4239  unsigned int mult, row, col;
4240  BYTE *start, *ptr;
4241 
4242  width = gm.gmBlackBoxX;
4243  height = gm.gmBlackBoxY;
4244  pitch = (width + 3) / 4 * 4;
4245  needed = pitch * height;
4246 
4247  if (!pvBuf || !cjBuf) break;
4248  if (!needed) return GDI_ERROR; /* empty glyph */
4249  if (needed > cjBuf)
4250  return GDI_ERROR;
4251 
4252  switch (ft_face->glyph->format)
4253  {
4255  {
4256  BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
4257  INT h = min( height, ft_face->glyph->bitmap.rows );
4258  INT x;
4259  while (h--)
4260  {
4261  for (x = 0; (UINT)x < pitch; x++)
4262  {
4263  if (x < ft_face->glyph->bitmap.width)
4264  dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4265  else
4266  dst[x] = 0;
4267  }
4268  src += ft_face->glyph->bitmap.pitch;
4269  dst += pitch;
4270  }
4271  break;
4272  }
4274  {
4275  ft_bitmap.width = width;
4276  ft_bitmap.rows = height;
4277  ft_bitmap.pitch = pitch;
4278  ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
4279  ft_bitmap.buffer = pvBuf;
4280 
4281  IntLockFreeType();
4282  if (needsTransform)
4283  {
4284  FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4285  }
4286  FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4287  RtlZeroMemory(ft_bitmap.buffer, cjBuf);
4288  FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
4290 
4291  if (iFormat == GGO_GRAY2_BITMAP)
4292  mult = 4;
4293  else if (iFormat == GGO_GRAY4_BITMAP)
4294  mult = 16;
4295  else if (iFormat == GGO_GRAY8_BITMAP)
4296  mult = 64;
4297  else
4298  {
4299  return GDI_ERROR;
4300  }
4301 
4302  start = pvBuf;
4303  for (row = 0; row < height; row++)
4304  {
4305  ptr = start;
4306  for (col = 0; col < width; col++, ptr++)
4307  {
4308  *ptr = (((int)*ptr) * mult + 128) / 256;
4309  }
4310  start += pitch;
4311  }
4312 
4313  break;
4314  }
4315  default:
4316  DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
4317  return GDI_ERROR;
4318  }
4319 
4320  break;
4321  }
4322 
4323  case GGO_NATIVE:
4324  {
4325  FT_Outline *outline = &ft_face->glyph->outline;
4326 
4327  if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
4328 
4329  IntLockFreeType();
4330  if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
4331 
4333 
4334  if (!pvBuf || !cjBuf)
4335  {
4337  break;
4338  }
4339  if (needed > cjBuf)
4340  {
4342  return GDI_ERROR;
4343  }
4346  break;
4347  }
4348 
4349  case GGO_BEZIER:
4350  {
4351  FT_Outline *outline = &ft_face->glyph->outline;
4352  if (cjBuf == 0) pvBuf = NULL;
4353 
4354  if (needsTransform && pvBuf)
4355  {
4356  IntLockFreeType();
4357  FT_Outline_Transform(outline, &transMat);
4359  }
4361 
4362  if (!pvBuf || !cjBuf)
4363  break;
4364  if (needed > cjBuf)
4365  return GDI_ERROR;
4366 
4368  break;
4369  }
4370 
4371  default:
4372  DPRINT1("Unsupported format %u\n", iFormat);
4373  return GDI_ERROR;
4374  }
4375 
4376  DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
4377  *pgm = gm;
4378  return needed;
4379 }
4380 
4381 BOOL
4382 FASTCALL
4384  PTEXTOBJ TextObj,
4385  LPCWSTR String,
4386  INT Count,
4387  ULONG MaxExtent,
4388  LPINT Fit,
4389  LPINT Dx,
4390  LPSIZE Size,
4391  FLONG fl)
4392 {
4393  PFONTGDI FontGDI;
4394  FT_Face face;
4395  FT_GlyphSlot glyph;
4396  FT_BitmapGlyph realglyph;
4397  INT error, glyph_index, i, previous;
4398  ULONGLONG TotalWidth64 = 0;
4399  BOOL use_kerning;
4400  FT_Render_Mode RenderMode;
4401  BOOLEAN Render;
4402  PMATRIX pmxWorldToDevice;
4403  LOGFONTW *plf;
4404  BOOL EmuBold, EmuItalic;
4405  LONG ascender, descender;
4406 
4407  FontGDI = ObjToGDI(TextObj->Font, FONT);
4408 
4409  face = FontGDI->SharedFace->Face;
4410  if (NULL != Fit)
4411  {
4412  *Fit = 0;
4413  }
4414 
4415  IntLockFreeType();
4416 
4417  TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
4418 
4419  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4420  EmuBold = EMUBOLD_NEEDED(FontGDI->OriginalWeight, plf->lfWeight);
4421  EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
4422 
4423  Render = IntIsFontRenderingEnabled();
4424  if (Render)
4425  RenderMode = IntGetFontRenderMode(plf);
4426  else
4427  RenderMode = FT_RENDER_MODE_MONO;
4428 
4429  /* Get the DC's world-to-device transformation matrix */
4430  pmxWorldToDevice = DC_pmxWorldToDevice(dc);
4431  FtSetCoordinateTransform(face, pmxWorldToDevice);
4432 
4433  use_kerning = FT_HAS_KERNING(face);
4434  previous = 0;
4435 
4436  for (i = 0; i < Count; i++)
4437  {
4438  glyph_index = get_glyph_index_flagged(face, *String, GTEF_INDICES, fl);
4439 
4440  if (EmuBold || EmuItalic)
4441  realglyph = NULL;
4442  else
4443  realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
4444  RenderMode, pmxWorldToDevice);
4445 
4446  if (EmuBold || EmuItalic || !realglyph)
4447  {
4448  error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
4449  if (error)
4450  {
4451  DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
4452  break;
4453  }
4454 
4455  glyph = face->glyph;
4456  if (EmuBold || EmuItalic)
4457  {
4458  if (EmuBold)
4459  FT_GlyphSlot_Embolden(glyph);
4460  if (EmuItalic)
4461  FT_GlyphSlot_Oblique(glyph);
4462  realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
4463  }
4464  else
4465  {
4466  realglyph = ftGdiGlyphCacheSet(face,
4467  glyph_index,
4468  plf->lfHeight,
4469  pmxWorldToDevice,
4470  glyph,
4471  RenderMode);
4472  }
4473 
4474  if (!realglyph)
4475  {
4476  DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
4477  break;
4478  }
4479  }
4480 
4481  /* Retrieve kerning distance */
4482  if (use_kerning && previous && glyph_index)
4483  {
4484  FT_Vector delta;
4485  FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
4486  TotalWidth64 += delta.x;
4487  }
4488 
4489  TotalWidth64 += realglyph->root.advance.x >> 10;
4490 
4491  if (((TotalWidth64 + 32) >> 6) <= MaxExtent && NULL != Fit)
4492  {
4493  *Fit = i + 1;
4494  }
4495  if (NULL != Dx)
4496  {
4497  Dx[i] = (TotalWidth64 + 32) >> 6;
4498  }
4499 
4500  /* Bold and italic do not use the cache */
4501  if (EmuBold || EmuItalic)
4502  {
4503  FT_Done_Glyph((FT_Glyph)realglyph);
4504  }
4505 
4506  previous = glyph_index;
4507  String++;
4508  }
4509  ASSERT(FontGDI->Magic == FONTGDI_MAGIC);
4510  ascender = FontGDI->tmAscent; /* Units above baseline */
4511  descender = FontGDI->tmDescent; /* Units below baseline */
4513 
4514  Size->cx = (TotalWidth64 + 32) >> 6;
4515  Size->cy = ascender + descender;
4516 
4517  return TRUE;
4518 }
4519 
4520 
4521 INT
4522 FASTCALL
4524  PDC Dc,
4525  LPFONTSIGNATURE lpSig,
4526  DWORD dwFlags)
4527 {
4528  PDC_ATTR pdcattr;
4529  UINT Ret = DEFAULT_CHARSET;
4530  INT i;
4531  HFONT hFont;
4532  PTEXTOBJ TextObj;
4533  PFONTGDI FontGdi;
4534  FONTSIGNATURE fs;
4535  TT_OS2 *pOS2;
4536  FT_Face Face;
4537  CHARSETINFO csi;
4538  DWORD cp, fs0;
4539  USHORT usACP, usOEM;
4540 
4541  pdcattr = Dc->pdcattr;
4542  hFont = pdcattr->hlfntNew;
4543  TextObj = RealizeFontInit(hFont);
4544 
4545  if (!TextObj)
4546  {
4548  return Ret;
4549  }
4550  FontGdi = ObjToGDI(TextObj->Font, FONT);
4551  Face = FontGdi->SharedFace->Face;
4552  TEXTOBJ_UnlockText(TextObj);
4553 
4554  memset(&fs, 0, sizeof(FONTSIGNATURE));
4555  IntLockFreeType();
4556  pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4557  if (NULL != pOS2)
4558  {
4559  fs.fsCsb[0] = pOS2->ulCodePageRange1;
4560  fs.fsCsb[1] = pOS2->ulCodePageRange2;
4561  fs.fsUsb[0] = pOS2->ulUnicodeRange1;
4562  fs.fsUsb[1] = pOS2->ulUnicodeRange2;
4563  fs.fsUsb[2] = pOS2->ulUnicodeRange3;
4564  fs.fsUsb[3] = pOS2->ulUnicodeRange4;
4565  if (pOS2->version == 0)
4566  {
4567  FT_UInt dummy;
4568 
4569  if (FT_Get_First_Char( Face, &dummy ) < 0x100)
4570  fs.fsCsb[0] |= FS_LATIN1;
4571  else
4572  fs.fsCsb[0] |= FS_SYMBOL;
4573  }
4574  }
4575  pOS2 = NULL;
4577  DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
4578  if (fs.fsCsb[0] == 0)
4579  { /* Let's see if we can find any interesting cmaps */
4580  for (i = 0; i < Face->num_charmaps; i++)
4581  {
4582  switch (Face->charmaps[i]->encoding)
4583  {
4584  case FT_ENCODING_UNICODE:
4585  case FT_ENCODING_APPLE_ROMAN:
4586  fs.fsCsb[0] |= FS_LATIN1;
4587  break;
4588  case FT_ENCODING_MS_SYMBOL:
4589  fs.fsCsb[0] |= FS_SYMBOL;
4590  break;
4591  default:
4592  break;
4593  }
4594  }
4595  }
4596  if (lpSig)
4597  {
4598  RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
4599  }
4600 
4601  RtlGetDefaultCodePage(&usACP, &usOEM);
4602  cp = usACP;
4603 
4605  if (csi.fs.fsCsb[0] & fs.fsCsb[0])
4606  {
4607  DPRINT("Hit 1\n");
4608  Ret = csi.ciCharset;
4609  goto Exit;
4610  }
4611 
4612  for (i = 0; i < MAXTCIINDEX; i++)
4613  {
4614  fs0 = 1L << i;
4615  if (fs.fsCsb[0] & fs0)
4616  {
4617  if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
4618  {
4619  // *cp = csi.ciACP;
4620  DPRINT("Hit 2\n");
4621  Ret = csi.ciCharset;
4622  goto Exit;
4623  }
4624  else
4625  DPRINT1("TCI failing on %x\n", fs0);
4626  }
4627  }
4628 Exit:
4629  DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
4630  return (MAKELONG(csi.ciACP, csi.ciCharset));
4631 }
4632 
4633 
4634 DWORD
4635 FASTCALL
4637 {
4638  DWORD size = 0;
4639  DWORD num_ranges = 0;
4640  FT_Face face = Font->SharedFace->Face;
4641 
4642  if (face->charmap->encoding == FT_ENCODING_UNICODE)
4643  {
4644  FT_UInt glyph_code = 0;
4645  FT_ULong char_code, char_code_prev;
4646 
4647  char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
4648 
4649  DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4650  face->num_glyphs, glyph_code, char_code);
4651 
4652  if (!glyph_code) return 0;
4653 
4654  if (glyphset)
4655  {
4656  glyphset->ranges[0].wcLow = (USHORT)char_code;
4657  glyphset->ranges[0].cGlyphs = 0;
4658  glyphset->cGlyphsSupported = 0;
4659  }
4660 
4661  num_ranges = 1;
4662  while (glyph_code)
4663  {
4664  if (char_code < char_code_prev)
4665  {
4666  DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
4667  return 0;
4668  }
4669  if (char_code - char_code_prev > 1)
4670  {
4671  num_ranges++;
4672  if (glyphset)
4673  {
4674  glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4675  glyphset->ranges[num_ranges - 1].cGlyphs = 1;
4676  glyphset->cGlyphsSupported++;
4677  }
4678  }
4679  else if (glyphset)
4680  {
4681  glyphset->ranges[num_ranges - 1].cGlyphs++;
4682  glyphset->cGlyphsSupported++;
4683  }
4684  char_code_prev = char_code;
4685  char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
4686  }
4687  }
4688  else
4689  DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
4690 
4691  size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4692  if (glyphset)
4693  {
4694  glyphset->cbThis = size;
4695  glyphset->cRanges = num_ranges;
4696  glyphset->flAccel = 0;
4697  }
4698  return size;
4699 }
4700 
4701 
4702 BOOL
4703 FASTCALL
4705  HDC hDC,
4706  PTMW_INTERNAL ptmwi)
4707 {
4708  PDC dc;
4709  PDC_ATTR pdcattr;
4710  PTEXTOBJ TextObj;
4711  PFONTGDI FontGDI;
4712  FT_Face Face;
4713  TT_OS2 *pOS2;
4714  TT_HoriHeader *pHori;
4715  FT_WinFNT_HeaderRec Win;
4716  ULONG Error;
4718  LOGFONTW *plf;
4719 
4720  if (!ptmwi)
4721  {
4723  return FALSE;
4724  }
4725 
4726  if (!(dc = DC_LockDc(hDC)))
4727  {
4729  return FALSE;
4730  }
4731  pdcattr = dc->pdcattr;
4732  TextObj = RealizeFontInit(pdcattr->hlfntNew);
4733  if (NULL != TextObj)
4734  {
4735  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4736  FontGDI = ObjToGDI(TextObj->Font, FONT);
4737&#