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