ReactOS  0.4.14-dev-593-g1793dcc
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  if ((FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent == 0)
2276  {
2277  Ascent = pHori->Ascender;
2278  Descent = -pHori->Descender;
2279  }
2280  else
2281  {
2282  Ascent = (FT_Short)pOS2->usWinAscent;
2283  Descent = (FT_Short)pOS2->usWinDescent;
2284  }
2285 
2286  TM->tmAscent = FontGDI->tmAscent;
2287  TM->tmDescent = FontGDI->tmDescent;
2288  TM->tmHeight = TM->tmAscent + TM->tmDescent;
2289  TM->tmInternalLeading = FontGDI->tmInternalLeading;
2290 
2291  /* MSDN says:
2292  * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2293  */
2294  TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
2295  - ((Ascent + Descent)
2296  - (pHori->Ascender - pHori->Descender)),
2297  YScale) + 32) >> 6);
2298 
2299  TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
2300  if (TM->tmAveCharWidth == 0)
2301  {
2302  TM->tmAveCharWidth = 1;
2303  }
2304 
2305  /* Correct forumla to get the maxcharwidth from unicode and ansi font */
2306  TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
2307 
2308  if (FontGDI->OriginalWeight != FW_DONTCARE &&
2309  FontGDI->OriginalWeight != FW_NORMAL)
2310  {
2311  TM->tmWeight = FontGDI->OriginalWeight;
2312  }
2313  else
2314  {
2315  TM->tmWeight = FontGDI->RequestWeight;
2316  }
2317 
2318  TM->tmOverhang = 0;
2319  TM->tmDigitizedAspectX = 96;
2320  TM->tmDigitizedAspectY = 96;
2321  if (face_has_symbol_charmap(Face) ||
2322  (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
2323  {
2324  USHORT cpOEM, cpAnsi;
2325 
2326  EngGetCurrentCodePage(&cpOEM, &cpAnsi);
2327  TM->tmFirstChar = 0;
2328  switch(cpAnsi)
2329  {
2330  case 1257: /* Baltic */
2331  TM->tmLastChar = 0xf8fd;
2332  break;
2333  default:
2334  TM->tmLastChar = 0xf0ff;
2335  }
2336  TM->tmBreakChar = 0x20;
2337  TM->tmDefaultChar = 0x1f;
2338  }
2339  else
2340  {
2341  TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
2342  TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
2343 
2344  if(pOS2->usFirstCharIndex <= 1)
2345  TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
2346  else if (pOS2->usFirstCharIndex > 0xff)
2347  TM->tmBreakChar = 0x20;
2348  else
2349  TM->tmBreakChar = pOS2->usFirstCharIndex;
2350  TM->tmDefaultChar = TM->tmBreakChar - 1;
2351  }
2352 
2353  if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
2354  {
2355  TM->tmItalic = 0xFF;
2356  }
2357  else
2358  {
2359  TM->tmItalic = 0;
2360  }
2361  TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
2362  TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
2363 
2364  if (!FT_IS_FIXED_WIDTH(Face))
2365  {
2366  switch (pOS2->panose[PAN_PROPORTION_INDEX])
2367  {
2368  case PAN_PROP_MONOSPACED:
2369  TM->tmPitchAndFamily = 0;
2370  break;
2371  default:
2373  break;
2374  }
2375  }
2376  else
2377  {
2378  TM->tmPitchAndFamily = 0;
2379  }
2380 
2381  switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
2382  {
2383  case PAN_FAMILY_SCRIPT:
2384  TM->tmPitchAndFamily |= FF_SCRIPT;
2385  break;
2386  case PAN_FAMILY_DECORATIVE:
2388  break;
2389 
2390  case PAN_ANY:
2391  case PAN_NO_FIT:
2393  case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
2394  /* Which is clearly not what the panose spec says. */
2395  if (TM->tmPitchAndFamily == 0) /* Fixed */
2396  {
2398  }
2399  else
2400  {
2401  switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
2402  {
2403  case PAN_ANY:
2404  case PAN_NO_FIT:
2405  default:
2407  break;
2408 
2409  case PAN_SERIF_COVE:
2410  case PAN_SERIF_OBTUSE_COVE:
2411  case PAN_SERIF_SQUARE_COVE:
2413  case PAN_SERIF_SQUARE:
2414  case PAN_SERIF_THIN:
2415  case PAN_SERIF_BONE:
2416  case PAN_SERIF_EXAGGERATED:
2417  case PAN_SERIF_TRIANGLE:
2418  TM->tmPitchAndFamily |= FF_ROMAN;
2419  break;
2420 
2421  case PAN_SERIF_NORMAL_SANS:
2422  case PAN_SERIF_OBTUSE_SANS:
2423  case PAN_SERIF_PERP_SANS:
2424  case PAN_SERIF_FLARED:
2425  case PAN_SERIF_ROUNDED:
2426  TM->tmPitchAndFamily |= FF_SWISS;
2427  break;
2428  }
2429  }
2430  break;
2431  default:
2433  }
2434 
2435  if (FT_IS_SCALABLE(Face))
2436  {
2438  }
2439  if (FT_IS_SFNT(Face))
2440  {
2442  }
2443 
2444  TM->tmCharSet = FontGDI->CharSet;
2445 }
2446 
2447 static NTSTATUS
2449  FT_UShort NameID, FT_UShort LangID);
2450 
2451 typedef struct FONT_NAMES
2452 {
2453  UNICODE_STRING FamilyNameW; /* family name (TT_NAME_ID_FONT_FAMILY) */
2454  UNICODE_STRING FaceNameW; /* face name (TT_NAME_ID_FULL_NAME) */
2455  UNICODE_STRING StyleNameW; /* style name (TT_NAME_ID_FONT_SUBFAMILY) */
2456  UNICODE_STRING FullNameW; /* unique name (TT_NAME_ID_UNIQUE_ID) */
2457  ULONG OtmSize; /* size of OUTLINETEXTMETRICW with extra data */
2459 
2460 static __inline void FASTCALL
2462 {
2463  ULONG OtmSize;
2464 
2465  RtlInitUnicodeString(&Names->FamilyNameW, NULL);
2466  RtlInitUnicodeString(&Names->FaceNameW, NULL);
2467  RtlInitUnicodeString(&Names->StyleNameW, NULL);
2468  RtlInitUnicodeString(&Names->FullNameW, NULL);
2469 
2470  /* family name */
2472  /* face name */
2474  /* style name */
2476  /* unique name (full name) */
2478 
2479  /* Calculate the size of OUTLINETEXTMETRICW with extra data */
2480  OtmSize = sizeof(OUTLINETEXTMETRICW) +
2481  Names->FamilyNameW.Length + sizeof(UNICODE_NULL) +
2482  Names->FaceNameW.Length + sizeof(UNICODE_NULL) +
2483  Names->StyleNameW.Length + sizeof(UNICODE_NULL) +
2484  Names->FullNameW.Length + sizeof(UNICODE_NULL);
2485  Names->OtmSize = OtmSize;
2486 }
2487 
2488 static __inline SIZE_T FASTCALL
2490 {
2491  RtlCopyMemory(pb, pName->Buffer, pName->Length);
2492  *(WCHAR *)&pb[pName->Length] = UNICODE_NULL;
2493  return pName->Length + sizeof(UNICODE_NULL);
2494 }
2495 
2496 static __inline BYTE *FASTCALL
2498 {
2499  BYTE *pb = (BYTE *)Otm + sizeof(OUTLINETEXTMETRICW);
2500 
2501  /* family name */
2502  Otm->otmpFamilyName = (LPSTR)(pb - (BYTE*) Otm);
2503  pb += IntStoreName(&Names->FamilyNameW, pb);
2504 
2505  /* face name */
2506  Otm->otmpFaceName = (LPSTR)(pb - (BYTE*) Otm);
2507  pb += IntStoreName(&Names->FaceNameW, pb);
2508 
2509  /* style name */
2510  Otm->otmpStyleName = (LPSTR)(pb - (BYTE*) Otm);
2511  pb += IntStoreName(&Names->StyleNameW, pb);
2512 
2513  /* unique name (full name) */
2514  Otm->otmpFullName = (LPSTR)(pb - (BYTE*) Otm);
2515  pb += IntStoreName(&Names->FullNameW, pb);
2516 
2517  return pb;
2518 }
2519 
2520 static __inline void FASTCALL
2522 {
2523  RtlFreeUnicodeString(&Names->FamilyNameW);
2524  RtlFreeUnicodeString(&Names->FaceNameW);
2525  RtlFreeUnicodeString(&Names->StyleNameW);
2526  RtlFreeUnicodeString(&Names->FullNameW);
2527 }
2528 
2529 /*************************************************************
2530  * IntGetOutlineTextMetrics
2531  *
2532  */
2533 INT FASTCALL
2535  UINT Size,
2536  OUTLINETEXTMETRICW *Otm)
2537 {
2538  TT_OS2 *pOS2;
2539  TT_HoriHeader *pHori;
2540  TT_Postscript *pPost;
2541  FT_Fixed XScale, YScale;
2542  FT_WinFNT_HeaderRec WinFNT;
2543  FT_Error Error;
2544  BYTE *pb;
2545  FONT_NAMES FontNames;
2546  PSHARED_FACE SharedFace = FontGDI->SharedFace;
2548  FT_Face Face = SharedFace->Face;
2549 
2551  {
2552  Cache = &SharedFace->EnglishUS;
2553  }
2554  else
2555  {
2556  Cache = &SharedFace->UserLanguage;
2557  }
2558 
2559  if (Size == 0 && Cache->OutlineRequiredSize > 0)
2560  {
2561  ASSERT(Otm == NULL);
2562  return Cache->OutlineRequiredSize;
2563  }
2564 
2565  IntInitFontNames(&FontNames, SharedFace);
2566  Cache->OutlineRequiredSize = FontNames.OtmSize;
2567 
2568  if (Size == 0)
2569  {
2570  ASSERT(Otm == NULL);
2571  IntFreeFontNames(&FontNames);
2572  return Cache->OutlineRequiredSize;
2573  }
2574 
2575  ASSERT(Otm != NULL);
2576 
2577  if (Size < Cache->OutlineRequiredSize)
2578  {
2579  DPRINT1("Size %u < OutlineRequiredSize %u\n", Size,
2580  Cache->OutlineRequiredSize);
2581  IntFreeFontNames(&FontNames);
2582  return 0; /* failure */
2583  }
2584 
2585  XScale = Face->size->metrics.x_scale;
2586  YScale = Face->size->metrics.y_scale;
2587 
2588  IntLockFreeType();
2589 
2590  pOS2 = FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
2591  pHori = FT_Get_Sfnt_Table(Face, FT_SFNT_HHEA);
2592  pPost = FT_Get_Sfnt_Table(Face, FT_SFNT_POST); /* We can live with this failing */
2593  Error = FT_Get_WinFNT_Header(Face, &WinFNT);
2594 
2595  if (pOS2 == NULL && Error)
2596  {
2598  DPRINT1("Can't find OS/2 table - not TT font?\n");
2599  IntFreeFontNames(&FontNames);
2600  return 0;
2601  }
2602 
2603  if (pHori == NULL && Error)
2604  {
2606  DPRINT1("Can't find HHEA table - not TT font?\n");
2607  IntFreeFontNames(&FontNames);
2608  return 0;
2609  }
2610 
2611  Otm->otmSize = Cache->OutlineRequiredSize;
2612 
2613  FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &WinFNT : 0);
2614 
2615  if (!pOS2)
2616  goto skip_os2;
2617 
2618  Otm->otmFiller = 0;
2620  Otm->otmfsSelection = pOS2->fsSelection;
2621  Otm->otmfsType = pOS2->fsType;
2622  Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2623  Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2624  Otm->otmItalicAngle = 0; /* POST table */
2625  Otm->otmEMSquare = Face->units_per_EM;
2626 
2627 #define SCALE_X(value) ((FT_MulFix((value), XScale) + 32) >> 6)
2628 #define SCALE_Y(value) ((FT_MulFix((value), YScale) + 32) >> 6)
2629 
2630  Otm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
2631  Otm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
2632  Otm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
2633  Otm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
2634  Otm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
2635  Otm->otmrcFontBox.left = SCALE_X(Face->bbox.xMin);
2636  Otm->otmrcFontBox.right = SCALE_X(Face->bbox.xMax);
2637  Otm->otmrcFontBox.top = SCALE_Y(Face->bbox.yMax);
2638  Otm->otmrcFontBox.bottom = SCALE_Y(Face->bbox.yMin);
2639  Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
2640  Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
2641  Otm->otmMacLineGap = Otm->otmLineGap;
2642  Otm->otmusMinimumPPEM = 0; /* TT Header */
2653 
2654  if (!pPost)
2655  {
2656  Otm->otmsUnderscoreSize = 0;
2657  Otm->otmsUnderscorePosition = 0;
2658  }
2659  else
2660  {
2663  }
2664 
2665 #undef SCALE_X
2666 #undef SCALE_Y
2667 
2668 skip_os2:
2670 
2671  pb = IntStoreFontNames(&FontNames, Otm);
2672  ASSERT(pb - (BYTE*)Otm == Cache->OutlineRequiredSize);
2673 
2674  IntFreeFontNames(&FontNames);
2675 
2676  return Cache->OutlineRequiredSize;
2677 }
2678 
2679 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
2680 static BYTE
2682 {
2683  /* FIXME: Add more and fix if wrong */
2684  switch (PRIMARYLANGID(LangID))
2685  {
2686  case LANG_CHINESE:
2687  switch (SUBLANGID(LangID))
2688  {
2690  return CHINESEBIG5_CHARSET;
2692  default:
2693  break;
2694  }
2695  return GB2312_CHARSET;
2696 
2697  case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
2698  case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
2699  return EASTEUROPE_CHARSET;
2700 
2701  case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
2702  case LANG_SERBIAN: case LANG_UKRAINIAN:
2703  return RUSSIAN_CHARSET;
2704 
2705  case LANG_ARABIC: return ARABIC_CHARSET;
2706  case LANG_GREEK: return GREEK_CHARSET;
2707  case LANG_HEBREW: return HEBREW_CHARSET;
2708  case LANG_JAPANESE: return SHIFTJIS_CHARSET;
2709  case LANG_KOREAN: return JOHAB_CHARSET;
2710  case LANG_TURKISH: return TURKISH_CHARSET;
2711  case LANG_THAI: return THAI_CHARSET;
2712  case LANG_LATVIAN: return BALTIC_CHARSET;
2713  case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
2714 
2715  case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
2716  case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
2717  case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
2718  case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
2719  case LANG_SWEDISH: default:
2720  return ANSI_CHARSET;
2721  }
2722 }
2723 
2724 static void
2726 {
2727  BYTE b, *pb = pvData;
2728  Size /= 2;
2729  while (Size-- > 0)
2730  {
2731  b = pb[0];
2732  pb[0] = pb[1];
2733  pb[1] = b;
2734  ++pb; ++pb;
2735  }
2736 }
2737 
2738 static NTSTATUS
2740  FT_UShort NameID, FT_UShort LangID)
2741 {
2742  FT_SfntName Name;
2743  INT i, Count, BestIndex, Score, BestScore;
2744  FT_Error Error;
2746  ANSI_STRING AnsiName;
2748  FT_Face Face = SharedFace->Face;
2749 
2750  RtlFreeUnicodeString(pNameW);
2751 
2752  /* select cache */
2753  if (PRIMARYLANGID(LangID) == LANG_ENGLISH)
2754  {
2755  Cache = &SharedFace->EnglishUS;
2756  }
2757  else
2758  {
2759  Cache = &SharedFace->UserLanguage;
2760  }
2761 
2762  /* use cache if available */
2763  if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer)
2764  {
2765  return DuplicateUnicodeString(&Cache->FontFamily, pNameW);
2766  }
2767  if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer)
2768  {
2769  return DuplicateUnicodeString(&Cache->FullName, pNameW);
2770  }
2771 
2772  BestIndex = -1;
2773  BestScore = 0;
2774 
2775  Count = FT_Get_Sfnt_Name_Count(Face);
2776  for (i = 0; i < Count; ++i)
2777  {
2778  Error = FT_Get_Sfnt_Name(Face, i, &Name);
2779  if (Error)
2780  {
2781  continue; /* failure */
2782  }
2783 
2784  if (Name.name_id != NameID)
2785  {
2786  continue; /* mismatched */
2787  }
2788 
2789  if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
2790  (Name.encoding_id != TT_MS_ID_UNICODE_CS &&
2791  Name.encoding_id != TT_MS_ID_SYMBOL_CS))
2792  {
2793  continue; /* not Microsoft Unicode name */
2794  }
2795 
2796  if (Name.string == NULL || Name.string_len == 0 ||
2797  (Name.string[0] == 0 && Name.string[1] == 0))
2798  {
2799  continue; /* invalid string */
2800  }
2801 
2802  if (Name.language_id == LangID)
2803  {
2804  Score = 30;
2805  BestIndex = i;
2806  break; /* best match */
2807  }
2808  else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID))
2809  {
2810  Score = 20;
2811  }
2812  else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH)
2813  {
2814  Score = 10;
2815  }
2816  else
2817  {
2818  Score = 0;
2819  }
2820 
2821  if (Score > BestScore)
2822  {
2823  BestScore = Score;
2824  BestIndex = i;
2825  }
2826  }
2827 
2828  if (BestIndex >= 0)
2829  {
2830  /* store the best name */
2831  Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
2832  if (!Error)
2833  {
2834  /* NOTE: Name.string is not null-terminated */
2835  UNICODE_STRING Tmp;
2836  Tmp.Buffer = (PWCH)Name.string;
2837  Tmp.Length = Tmp.MaximumLength = Name.string_len;
2838 
2839  pNameW->Length = 0;
2840  pNameW->MaximumLength = Name.string_len + sizeof(WCHAR);
2842 
2843  if (pNameW->Buffer)
2844  {
2845  Status = RtlAppendUnicodeStringToString(pNameW, &Tmp);
2846  if (Status == STATUS_SUCCESS)
2847  {
2848  /* Convert UTF-16 big endian to little endian */
2849  SwapEndian(pNameW->Buffer, pNameW->Length);
2850  }
2851  }
2852  else
2853  {
2855  }
2856  }
2857  }
2858 
2859  if (!NT_SUCCESS(Status))
2860  {
2861  /* defaulted */
2862  if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
2863  {
2864  RtlInitAnsiString(&AnsiName, Face->style_name);
2865  Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2866  }
2867  else
2868  {
2869  RtlInitAnsiString(&AnsiName, Face->family_name);
2870  Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2871  }
2872  }
2873 
2874  if (NT_SUCCESS(Status))
2875  {
2876  /* make cache */
2877  if (NameID == TT_NAME_ID_FONT_FAMILY)
2878  {
2880  IntLockFreeType();
2881  if (!Cache->FontFamily.Buffer)
2882  DuplicateUnicodeString(pNameW, &Cache->FontFamily);
2884  }
2885  else if (NameID == TT_NAME_ID_FULL_NAME)
2886  {
2888  IntLockFreeType();
2889  if (!Cache->FullName.Buffer)
2890  DuplicateUnicodeString(pNameW, &Cache->FullName);
2892  }
2893  }
2894 
2895  return Status;
2896 }
2897 
2898 static void FASTCALL
2900  LPCWSTR FullName, PFONTGDI FontGDI)
2901 {
2902  ANSI_STRING StyleA;
2903  UNICODE_STRING StyleW;
2904  TT_OS2 *pOS2;
2905  FONTSIGNATURE fs;
2906  CHARSETINFO CharSetInfo;
2907  unsigned i, Size;
2908  OUTLINETEXTMETRICW *Otm;
2909  LOGFONTW *Lf;
2910  TEXTMETRICW *TM;
2911  NEWTEXTMETRICW *Ntm;
2912  DWORD fs0;
2913  NTSTATUS status;
2914  PSHARED_FACE SharedFace = FontGDI->SharedFace;
2915  FT_Face Face = SharedFace->Face;
2916  UNICODE_STRING NameW;
2917 
2918  RtlInitUnicodeString(&NameW, NULL);
2919  RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
2920  Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2922  if (!Otm)
2923  {
2924  return;
2925  }
2926  Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2927  if (!Size)
2928  {
2930  return;
2931  }
2932 
2933  Lf = &Info->EnumLogFontEx.elfLogFont;
2934  TM = &Otm->otmTextMetrics;
2935 
2936  Lf->lfHeight = TM->tmHeight;
2937  Lf->lfWidth = TM->tmAveCharWidth;
2938  Lf->lfWeight = TM->tmWeight;
2939  Lf->lfItalic = TM->tmItalic;
2940  Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
2941  Lf->lfCharSet = TM->tmCharSet;
2944  Lf->lfQuality = PROOF_QUALITY;
2945 
2946  Ntm = &Info->NewTextMetricEx.ntmTm;
2947  Ntm->tmHeight = TM->tmHeight;
2948  Ntm->tmAscent = TM->tmAscent;
2949  Ntm->tmDescent = TM->tmDescent;
2952  Ntm->tmAveCharWidth = TM->tmAveCharWidth;
2953  Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
2954  Ntm->tmWeight = TM->tmWeight;
2955  Ntm->tmOverhang = TM->tmOverhang;
2958  Ntm->tmFirstChar = TM->tmFirstChar;
2959  Ntm->tmLastChar = TM->tmLastChar;
2960  Ntm->tmDefaultChar = TM->tmDefaultChar;
2961  Ntm->tmBreakChar = TM->tmBreakChar;
2962  Ntm->tmItalic = TM->tmItalic;
2963  Ntm->tmUnderlined = TM->tmUnderlined;
2964  Ntm->tmStruckOut = TM->tmStruckOut;
2966  Ntm->tmCharSet = TM->tmCharSet;
2967  Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
2968 
2969  if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
2970 
2971  if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
2972 
2973  Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
2974  ? TRUETYPE_FONTTYPE : 0);
2975 
2976  if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
2977  Info->FontType |= RASTER_FONTTYPE;
2978 
2979 
2980  /* face name */
2981  if (!FaceName)
2982  FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
2983 
2984  RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
2985 
2986  /* full name */
2987  if (!FullName)
2988  FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName);
2989 
2990  RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2991  sizeof(Info->EnumLogFontEx.elfFullName),
2992  FullName);
2993 
2994  RtlInitAnsiString(&StyleA, Face->style_name);
2995  StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
2996  StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
2997  status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
2998  if (!NT_SUCCESS(status))
2999  {
3001  return;
3002  }
3003  Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
3004 
3005  IntLockFreeType();
3006  pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3007 
3008  if (!pOS2)
3009  {
3012  return;
3013  }
3014 
3015  Ntm->ntmSizeEM = Otm->otmEMSquare;
3016  Ntm->ntmCellHeight = (FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent;
3017  Ntm->ntmAvgWidth = 0;
3018 
3020 
3021  fs.fsCsb[0] = pOS2->ulCodePageRange1;
3022  fs.fsCsb[1] = pOS2->ulCodePageRange2;
3023  fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3024  fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3025  fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3026  fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3027 
3028  if (0 == pOS2->version)
3029  {
3030  FT_UInt Dummy;
3031 
3032  if (FT_Get_First_Char(Face, &Dummy) < 0x100)
3033  fs.fsCsb[0] |= FS_LATIN1;
3034  else
3035  fs.fsCsb[0] |= FS_SYMBOL;
3036  }
3038 
3039  if (fs.fsCsb[0] == 0)
3040  {
3041  /* Let's see if we can find any interesting cmaps */
3042  for (i = 0; i < (UINT)Face->num_charmaps; i++)
3043  {
3044  switch (Face->charmaps[i]->encoding)
3045  {
3046  case FT_ENCODING_UNICODE:
3047  case FT_ENCODING_APPLE_ROMAN:
3048  fs.fsCsb[0] |= FS_LATIN1;
3049  break;
3050  case FT_ENCODING_MS_SYMBOL:
3051  fs.fsCsb[0] |= FS_SYMBOL;
3052  break;
3053  default:
3054  break;
3055  }
3056  }
3057  }
3058 
3059  for (i = 0; i < MAXTCIINDEX; i++)
3060  {
3061  fs0 = 1L << i;
3062  if (fs.fsCsb[0] & fs0)
3063  {
3064  if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
3065  {
3066  CharSetInfo.ciCharset = DEFAULT_CHARSET;
3067  }
3068  if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
3069  {
3070  if (g_ElfScripts[i])
3071  wcscpy(Info->EnumLogFontEx.elfScript, g_ElfScripts[i]);
3072  else
3073  {
3074  DPRINT1("Unknown elfscript for bit %u\n", i);
3075  }
3076  }
3077  }
3078  }
3079  Info->NewTextMetricEx.ntmFontSig = fs;
3080 }
3081 
3082 static BOOLEAN FASTCALL
3085  LPCWSTR NominalName,
3086  LONG *pCount,
3087  LONG MaxCount,
3088  PLIST_ENTRY Head)
3089 {
3091  PFONT_ENTRY CurrentEntry;
3092  FONTGDI *FontGDI;
3093  FONTFAMILYINFO InfoEntry;
3094  LONG Count = *pCount;
3095 
3096  for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
3097  {
3098  CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
3099  FontGDI = CurrentEntry->Font;
3100  ASSERT(FontGDI);
3101 
3102  if (LogFont->lfCharSet != DEFAULT_CHARSET &&
3103  LogFont->lfCharSet != FontGDI->CharSet)
3104  {
3105  continue; /* charset mismatch */
3106  }
3107 
3108  /* get one info entry */
3109  FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
3110 
3111  if (LogFont->lfFaceName[0] != UNICODE_NULL)
3112  {
3113  /* check name */
3114  if (_wcsnicmp(LogFont->lfFaceName,
3116  RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0 &&
3117  _wcsnicmp(LogFont->lfFaceName,
3118  InfoEntry.EnumLogFontEx.elfFullName,
3119  RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0)
3120  {
3121  continue;
3122  }
3123  }
3124 
3125  if (NominalName)
3126  {
3127  /* store the nominal name */
3129  sizeof(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName),
3130  NominalName);
3131  }
3132 
3133  /* store one entry to Info */
3134  if (0 <= Count && Count < MaxCount)
3135  {
3136  RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
3137  }
3138  Count++;
3139  }
3140 
3141  *pCount = Count;
3142 
3143  return TRUE;
3144 }
3145 
3146 static BOOLEAN FASTCALL
3149  LONG *pCount,
3150  LONG MaxCount)
3151 {
3152  PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead;
3153  PFONTSUBST_ENTRY pCurrentEntry;
3154  PUNICODE_STRING pFromW, pToW;
3155  LOGFONTW lf = *LogFont;
3157 
3158  for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
3159  {
3160  pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
3161 
3162  pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
3163  if (LogFont->lfFaceName[0] != UNICODE_NULL)
3164  {
3165  /* check name */
3166  if (_wcsicmp(LogFont->lfFaceName, pFromW->Buffer) != 0)
3167  continue; /* mismatch */
3168  }
3169 
3170  pToW = &pCurrentEntry->FontNames[FONTSUBST_TO];
3171  if (RtlEqualUnicodeString(pFromW, pToW, TRUE) &&
3172  pCurrentEntry->CharSets[FONTSUBST_FROM] ==
3173  pCurrentEntry->CharSets[FONTSUBST_TO])
3174  {
3175  /* identical mapping */
3176  continue;
3177  }
3178 
3179  /* substitute and get the real name */
3180  IntUnicodeStringToBuffer(lf.lfFaceName, sizeof(lf.lfFaceName), pFromW);
3181  SubstituteFontRecurse(&lf);
3182  if (LogFont->lfCharSet != DEFAULT_CHARSET && LogFont->lfCharSet != lf.lfCharSet)
3183  continue;
3184 
3185  /* search in global fonts */
3187  GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount, &g_FontListHead);
3189 
3190  /* search in private fonts */
3191  IntLockProcessPrivateFonts(Win32Process);
3192  GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount,
3193  &Win32Process->PrivateFontListHead);
3194  IntUnLockProcessPrivateFonts(Win32Process);
3195 
3196  if (LogFont->lfFaceName[0] != UNICODE_NULL)
3197  {
3198  /* it's already matched to the exact name and charset if the name
3199  was specified at here, then so don't scan more for another name */
3200  break;
3201  }
3202  }
3203 
3204  return TRUE;
3205 }
3206 
3207 BOOL
3208 FASTCALL
3210 {
3211  if ( lprs )
3212  {
3213  lprs->nSize = sizeof(RASTERIZER_STATUS);
3214  lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
3215  lprs->nLanguageID = gusLanguageID;
3216  return TRUE;
3217  }
3219  return FALSE;
3220 }
3221 
3222 static
3223 BOOL
3225  PMATRIX pmx1,
3226  PMATRIX pmx2)
3227 {
3228  return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
3229  FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
3230  FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
3231  FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
3232 }
3233 
3236  FT_Face Face,
3237  INT GlyphIndex,
3238  INT Height,
3239  FT_Render_Mode RenderMode,
3240  PMATRIX pmx)
3241 {
3242  PLIST_ENTRY CurrentEntry;
3243  PFONT_CACHE_ENTRY FontEntry;
3244 
3246 
3247  for (CurrentEntry = g_FontCacheListHead.Flink;
3248  CurrentEntry != &g_FontCacheListHead;
3249  CurrentEntry = CurrentEntry->Flink)
3250  {
3251  FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
3252  if ((FontEntry->Face == Face) &&
3253  (FontEntry->GlyphIndex == GlyphIndex) &&
3254  (FontEntry->Height == Height) &&
3255  (FontEntry->RenderMode == RenderMode) &&
3256  (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
3257  break;
3258  }
3259 
3260  if (CurrentEntry == &g_FontCacheListHead)
3261  {
3262  return NULL;
3263  }
3264 
3265  RemoveEntryList(CurrentEntry);
3266  InsertHeadList(&g_FontCacheListHead, CurrentEntry);
3267  return FontEntry->BitmapGlyph;
3268 }
3269 
3270 /* no cache */
3273  FT_Face Face,
3274  FT_GlyphSlot GlyphSlot,
3275  FT_Render_Mode RenderMode)
3276 {
3277  FT_Glyph Glyph;
3278  INT error;
3279  FT_Bitmap AlignedBitmap;
3280  FT_BitmapGlyph BitmapGlyph;
3281 
3282  error = FT_Get_Glyph(GlyphSlot, &Glyph);
3283  if (error)
3284  {
3285  DPRINT1("Failure getting glyph.\n");
3286  return NULL;
3287  }
3288 
3289  error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
3290  if (error)
3291  {
3292  FT_Done_Glyph(Glyph);
3293  DPRINT1("Failure rendering glyph.\n");
3294  return NULL;
3295  }
3296 
3297  BitmapGlyph = (FT_BitmapGlyph)Glyph;
3298  FT_Bitmap_New(&AlignedBitmap);
3299  if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
3300  {
3301  DPRINT1("Conversion failed\n");
3302  FT_Done_Glyph((FT_Glyph)BitmapGlyph);
3303  return NULL;
3304  }
3305 
3306  FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
3307  BitmapGlyph->bitmap = AlignedBitmap;
3308 
3309  return BitmapGlyph;
3310 }
3311 
3314  FT_Face Face,
3315  INT GlyphIndex,
3316  INT Height,
3317  PMATRIX pmx,
3318  FT_GlyphSlot GlyphSlot,
3319  FT_Render_Mode RenderMode)
3320 {
3321  FT_Glyph GlyphCopy;
3322  INT error;
3323  PFONT_CACHE_ENTRY NewEntry;
3324  FT_Bitmap AlignedBitmap;
3325  FT_BitmapGlyph BitmapGlyph;
3326 
3328 
3329  error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
3330  if (error)
3331  {
3332  DPRINT1("Failure caching glyph.\n");
3333  return NULL;
3334  };
3335 
3336  error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
3337  if (error)
3338  {
3339  FT_Done_Glyph(GlyphCopy);
3340  DPRINT1("Failure rendering glyph.\n");
3341  return NULL;
3342  };
3343 
3345  if (!NewEntry)
3346  {
3347  DPRINT1("Alloc failure caching glyph.\n");
3348  FT_Done_Glyph(GlyphCopy);
3349  return NULL;
3350  }
3351 
3352  BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
3353  FT_Bitmap_New(&AlignedBitmap);
3354  if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
3355  {
3356  DPRINT1("Conversion failed\n");
3357  ExFreePoolWithTag(NewEntry, TAG_FONT);
3358  FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
3359  FT_Done_Glyph((FT_Glyph)BitmapGlyph);
3360  return NULL;
3361  }
3362 
3363  FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
3364  BitmapGlyph->bitmap = AlignedBitmap;
3365 
3366  NewEntry->GlyphIndex = GlyphIndex;
3367  NewEntry->Face = Face;
3368  NewEntry->BitmapGlyph = BitmapGlyph;
3369  NewEntry->Height = Height;
3370  NewEntry->RenderMode = RenderMode;
3371  NewEntry->mxWorldToDevice = *pmx;
3372 
3375  {
3377  RemoveCachedEntry(NewEntry);
3378  }
3379 
3380  return BitmapGlyph;
3381 }
3382 
3383 
3384 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3385 {
3386  TTPOLYGONHEADER *pph;
3387  TTPOLYCURVE *ppc;
3388  int needed = 0, point = 0, contour, first_pt;
3389  unsigned int pph_start, cpfx;
3390  DWORD type;
3391 
3392  for (contour = 0; contour < outline->n_contours; contour++)
3393  {
3394  /* Ignore contours containing one point */
3395  if (point == outline->contours[contour])
3396  {
3397  point++;
3398  continue;
3399  }
3400 
3401  pph_start = needed;
3402  pph = (TTPOLYGONHEADER *)(buf + needed);
3403  first_pt = point;
3404  if (buf)
3405  {
3406  pph->dwType = TT_POLYGON_TYPE;
3407  FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3408  }
3409  needed += sizeof(*pph);
3410  point++;
3411  while (point <= outline->contours[contour])
3412  {
3413  ppc = (TTPOLYCURVE *)(buf + needed);
3414  type = outline->tags[point] & FT_Curve_Tag_On ?
3416  cpfx = 0;
3417  do
3418  {
3419  if (buf)
3420  FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3421  cpfx++;
3422  point++;
3423  } while (point <= outline->contours[contour] &&
3424  (outline->tags[point] & FT_Curve_Tag_On) ==
3425  (outline->tags[point-1] & FT_Curve_Tag_On));
3426  /* At the end of a contour Windows adds the start point, but
3427  only for Beziers */
3428  if (point > outline->contours[contour] &&
3429  !(outline->tags[point-1] & FT_Curve_Tag_On))
3430  {
3431  if (buf)
3432  FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3433  cpfx++;
3434  }
3435  else if (point <= outline->contours[contour] &&
3436  outline->tags[point] & FT_Curve_Tag_On)
3437  {
3438  /* add closing pt for bezier */
3439  if (buf)
3440  FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3441  cpfx++;
3442  point++;
3443  }
3444  if (buf)
3445  {
3446  ppc->wType = type;
3447  ppc->cpfx = cpfx;
3448  }
3449  needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3450  }
3451  if (buf)
3452  pph->cb = needed - pph_start;
3453  }
3454  return needed;
3455 }
3456 
3457 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3458 {
3459  /* Convert the quadratic Beziers to cubic Beziers.
3460  The parametric eqn for a cubic Bezier is, from PLRM:
3461  r(t) = at^3 + bt^2 + ct + r0
3462  with the control points:
3463  r1 = r0 + c/3
3464  r2 = r1 + (c + b)/3
3465  r3 = r0 + c + b + a
3466 
3467  A quadratic Bezier has the form:
3468  p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3469 
3470  So equating powers of t leads to:
3471  r1 = 2/3 p1 + 1/3 p0
3472  r2 = 2/3 p1 + 1/3 p2
3473  and of course r0 = p0, r3 = p2
3474  */
3475  int contour, point = 0, first_pt;
3476  TTPOLYGONHEADER *pph;
3477  TTPOLYCURVE *ppc;
3478  DWORD pph_start, cpfx, type;
3479  FT_Vector cubic_control[4];
3480  unsigned int needed = 0;
3481 
3482  for (contour = 0; contour < outline->n_contours; contour++)
3483  {
3484  pph_start = needed;
3485  pph = (TTPOLYGONHEADER *)(buf + needed);
3486  first_pt = point;
3487  if (buf)
3488  {
3489  pph->dwType = TT_POLYGON_TYPE;
3490  FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3491  }
3492  needed += sizeof(*pph);
3493  point++;
3494  while (point <= outline->contours[contour])
3495  {
3496  ppc = (TTPOLYCURVE *)(buf + needed);
3497  type = outline->tags[point] & FT_Curve_Tag_On ?
3499  cpfx = 0;
3500  do
3501  {
3502  if (type == TT_PRIM_LINE)
3503  {
3504  if (buf)
3505  FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3506  cpfx++;
3507  point++;
3508  }
3509  else
3510  {
3511  /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3512  so cpfx = 3n */
3513 
3514  /* FIXME: Possible optimization in endpoint calculation
3515  if there are two consecutive curves */
3516  cubic_control[0] = outline->points[point-1];
3517  if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3518  {
3519  cubic_control[0].x += outline->points[point].x + 1;
3520  cubic_control[0].y += outline->points[point].y + 1;
3521  cubic_control[0].x >>= 1;
3522  cubic_control[0].y >>= 1;
3523  }
3524  if (point+1 > outline->contours[contour])
3525  cubic_control[3] = outline->points[first_pt];
3526  else
3527  {
3528  cubic_control[3] = outline->points[point+1];
3529  if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3530  {
3531  cubic_control[3].x += outline->points[point].x + 1;
3532  cubic_control[3].y += outline->points[point].y + 1;
3533  cubic_control[3].x >>= 1;
3534  cubic_control[3].y >>= 1;
3535  }
3536  }
3537  /* r1 = 1/3 p0 + 2/3 p1
3538  r2 = 1/3 p2 + 2/3 p1 */
3539  cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3540  cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3541  cubic_control[2] = cubic_control[1];
3542  cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3543  cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3544  cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3545  cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3546  if (buf)
3547  {
3548  FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3549  FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3550  FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3551  }
3552  cpfx += 3;
3553  point++;
3554  }
3555  } while (point <= outline->contours[contour] &&
3556  (outline->tags[point] & FT_Curve_Tag_On) ==
3557  (outline->tags[point-1] & FT_Curve_Tag_On));
3558  /* At the end of a contour Windows adds the start point,
3559  but only for Beziers and we've already done that.
3560  */
3561  if (point <= outline->contours[contour] &&
3562  outline->tags[point] & FT_Curve_Tag_On)
3563  {
3564  /* This is the closing pt of a bezier, but we've already
3565  added it, so just inc point and carry on */
3566  point++;
3567  }
3568  if (buf)
3569  {
3570  ppc->wType = type;
3571  ppc->cpfx = cpfx;
3572  }
3573  needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3574  }
3575  if (buf)
3576  pph->cb = needed - pph_start;
3577  }
3578  return needed;
3579 }
3580 
3581 static FT_Error
3582 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
3583 {
3584  FT_Error error;
3585  FT_Size_RequestRec req;
3586  FT_Face face = FontGDI->SharedFace->Face;
3587  TT_OS2 *pOS2;
3588  TT_HoriHeader *pHori;
3589  FT_WinFNT_HeaderRec WinFNT;
3590  LONG Ascent, Descent, Sum, EmHeight64;
3591 
3592  lfWidth = abs(lfWidth);
3593  if (lfHeight == 0)
3594  {
3595  if (lfWidth == 0)
3596  {
3597  DPRINT("lfHeight and lfWidth are zero.\n");
3598  lfHeight = -16;
3599  }
3600  else
3601  {
3602  lfHeight = lfWidth;
3603  }
3604  }
3605 
3606  if (lfHeight == -1)
3607  lfHeight = -2;
3608 
3612 
3613  if (!pOS2 || !pHori)
3614  {
3615  error = FT_Get_WinFNT_Header(face, &WinFNT);
3616  if (error)
3617  {
3618  DPRINT1("%s: Failed to request font size.\n", face->family_name);
3619  ASSERT(FALSE);
3620  return error;
3621  }
3622 
3623  FontGDI->tmHeight = WinFNT.pixel_height;
3624  FontGDI->tmAscent = WinFNT.ascent;
3625  FontGDI->tmDescent = FontGDI->tmHeight - FontGDI->tmAscent;
3626  FontGDI->tmInternalLeading = WinFNT.internal_leading;
3627  FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3628  FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3629  FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3630  FontGDI->Magic = FONTGDI_MAGIC;
3631  return 0;
3632  }
3633 
3634  /*
3635  * NOTE: We cast TT_OS2.usWinAscent and TT_OS2.usWinDescent to signed FT_Short.
3636  * Why? See: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswindescent
3637  *
3638  * > usWinDescent is "usually" a positive value ...
3639  *
3640  * We can read it as "not always". See CORE-14994.
3641  * See also: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fsselection
3642  */
3643 #define FM_SEL_USE_TYPO_METRICS 0x80
3644  if (lfHeight > 0)
3645  {
3646  /* case (A): lfHeight is positive */
3647  Sum = (FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent;
3648  if (Sum == 0 || (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS))
3649  {
3650  Ascent = pHori->Ascender;
3651  Descent = -pHori->Descender;
3652  Sum = Ascent + Descent;
3653  }
3654  else
3655  {
3656  Ascent = (FT_Short)pOS2->usWinAscent;
3657  Descent = (FT_Short)pOS2->usWinDescent;
3658  }
3659 
3660  FontGDI->tmAscent = FT_MulDiv(lfHeight, Ascent, Sum);
3661  FontGDI->tmDescent = FT_MulDiv(lfHeight, Descent, Sum);
3662  FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3663  FontGDI->tmInternalLeading = FontGDI->tmHeight - FT_MulDiv(lfHeight, face->units_per_EM, Sum);
3664  }
3665  else if (lfHeight < 0)
3666  {
3667  /* case (B): lfHeight is negative */
3669  {
3670  FontGDI->tmAscent = FT_MulDiv(-lfHeight, pHori->Ascender, face->units_per_EM);
3671  FontGDI->tmDescent = FT_MulDiv(-lfHeight, -pHori->Descender, face->units_per_EM);
3672  }
3673  else
3674  {
3675  FontGDI->tmAscent = FT_MulDiv(-lfHeight, (FT_Short)pOS2->usWinAscent, face->units_per_EM);
3676  FontGDI->tmDescent = FT_MulDiv(-lfHeight, (FT_Short)pOS2->usWinDescent, face->units_per_EM);
3677  }
3678  FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3679  FontGDI->tmInternalLeading = FontGDI->tmHeight + lfHeight;
3680  }
3681 #undef FM_SEL_USE_TYPO_METRICS
3682 
3683  FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3684  FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3685  FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3686  FontGDI->Magic = FONTGDI_MAGIC;
3687 
3688  EmHeight64 = (FontGDI->EmHeight << 6);
3689 
3691  req.width = 0;
3692  req.height = EmHeight64;
3693  req.horiResolution = 0;
3694  req.vertResolution = 0;
3695  return FT_Request_Size(face, &req);
3696 }
3697 
3698 BOOL
3699 FASTCALL
3701  PTEXTOBJ TextObj,
3702  PFONTGDI FontGDI,
3703  BOOL bDoLock)
3704 {
3705  FT_Face face;
3706  INT error, n;
3707  FT_CharMap charmap, found;
3708  LOGFONTW *plf;
3709 
3710  if (bDoLock)
3711  IntLockFreeType();
3712 
3713  face = FontGDI->SharedFace->Face;
3714  if (face->charmap == NULL)
3715  {
3716  DPRINT("WARNING: No charmap selected!\n");
3717  DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3718 
3719  found = NULL;
3720  for (n = 0; n < face->num_charmaps; n++)
3721  {
3722  charmap = face->charmaps[n];
3723  if (charmap->encoding == FT_ENCODING_UNICODE)
3724  {
3725  found = charmap;
3726  break;
3727  }
3728  }
3729  if (!found)
3730  {
3731  for (n = 0; n < face->num_charmaps; n++)
3732  {
3733  charmap = face->charmaps[n];
3734  if (charmap->platform_id == TT_PLATFORM_APPLE_UNICODE)
3735  {
3736  found = charmap;
3737  break;
3738  }
3739  }
3740  }
3741  if (!found)
3742  {
3743  for (n = 0; n < face->num_charmaps; n++)
3744  {
3745  charmap = face->charmaps[n];
3746  if (charmap->encoding == FT_ENCODING_MS_SYMBOL)
3747  {
3748  found = charmap;
3749  break;
3750  }
3751  }
3752  }
3753  if (!found && face->num_charmaps > 0)
3754  {
3755  found = face->charmaps[0];
3756  }
3757  if (!found)
3758  {
3759  DPRINT1("WARNING: Could not find desired charmap!\n");
3760  }
3761  else
3762  {
3763  DPRINT("Found charmap encoding: %i\n", found->encoding);
3764  error = FT_Set_Charmap(face, found);
3765  if (error)
3766  {
3767  DPRINT1("WARNING: Could not set the charmap!\n");
3768  }
3769  }
3770  }
3771 
3772  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3773 
3774  error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
3775 
3776  if (bDoLock)
3778 
3779  if (error)
3780  {
3781  DPRINT1("Error in setting pixel sizes: %d\n", error);
3782  return FALSE;
3783  }
3784 
3785  return TRUE;
3786 }
3787 
3788 static inline FT_UInt FASTCALL
3790 {
3791  FT_UInt ret;
3792 
3793  if (glyph < 0x100) glyph += 0xf000;
3794  /* there are a number of old pre-Unicode "broken" TTFs, which
3795  do have symbols at U+00XX instead of U+f0XX */
3796  if (!(ret = FT_Get_Char_Index(ft_face, glyph)))
3797  ret = FT_Get_Char_Index(ft_face, glyph - 0xf000);
3798 
3799  return ret;
3800 }
3801 
3802 static inline FT_UInt FASTCALL
3804 {
3805  FT_UInt ret;
3806 
3807  if (face_has_symbol_charmap(ft_face))
3808  {
3809  ret = get_glyph_index_symbol(ft_face, glyph);
3810  if (ret != 0)
3811  return ret;
3812  }
3813 
3814  return FT_Get_Char_Index(ft_face, glyph);
3815 }
3816 
3817 static inline FT_UInt FASTCALL
3819 {
3820  FT_UInt glyph_index;
3821  if (flags & indexed_flag)
3822  {
3823  glyph_index = code;
3824  }
3825  else
3826  {
3827  glyph_index = get_glyph_index(face, code);
3828  }
3829  return glyph_index;
3830 }
3831 
3832 /*
3833  * Based on WineEngGetGlyphOutline
3834  *
3835  */
3836 ULONG
3837 FASTCALL
3839  PDC dc,
3840  WCHAR wch,
3841  UINT iFormat,
3842  LPGLYPHMETRICS pgm,
3843  ULONG cjBuf,
3844  PVOID pvBuf,
3845  LPMAT2 pmat2,
3846  BOOL bIgnoreRotation)
3847 {
3848  PDC_ATTR pdcattr;
3849  PTEXTOBJ TextObj;
3850  PFONTGDI FontGDI;
3851  HFONT hFont = 0;
3852  GLYPHMETRICS gm;
3853  ULONG Size;
3854  FT_Face ft_face;
3855  FT_UInt glyph_index;
3856  DWORD width, height, pitch, needed = 0;
3857  FT_Bitmap ft_bitmap;
3858  FT_Error error;
3859  INT left, right, top = 0, bottom = 0;
3861  FLOATOBJ eM11, widthRatio, eTemp;
3862  FT_Matrix transMat = identityMat;
3863  BOOL needsTransform = FALSE;
3864  INT orientation;
3865  LONG aveWidth;
3866  INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3867  OUTLINETEXTMETRICW *potm;
3868  XFORMOBJ xo;
3869  XFORML xform;
3870  LOGFONTW *plf;
3871 
3872  DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3873  cjBuf, pvBuf, pmat2);
3874 
3875  pdcattr = dc->pdcattr;
3876 
3877  XFORMOBJ_vInit(&xo, &dc->pdcattr->mxWorldToDevice);
3878  XFORMOBJ_iGetXform(&xo, &xform);
3879  FLOATOBJ_SetFloat(&eM11, xform.eM11);
3880 
3881  hFont = pdcattr->hlfntNew;
3882  TextObj = RealizeFontInit(hFont);
3883 
3884  if (!TextObj)
3885  {
3887  return GDI_ERROR;
3888  }
3889  FontGDI = ObjToGDI(TextObj->Font, FONT);
3890  ft_face = FontGDI->SharedFace->Face;
3891 
3892  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3893  aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3894  orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3895 
3896  Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3898  if (!potm)
3899  {
3901  TEXTOBJ_UnlockText(TextObj);
3902  return GDI_ERROR;
3903  }
3904  Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
3905  if (!Size)
3906  {
3907  /* FIXME: last error? */
3909  TEXTOBJ_UnlockText(TextObj);
3910  return GDI_ERROR;
3911  }
3912 
3913  IntLockFreeType();
3914  TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3916 
3917  TEXTOBJ_UnlockText(TextObj);
3918 
3919  glyph_index = get_glyph_index_flagged(ft_face, wch, GGO_GLYPH_INDEX, iFormat);
3921 
3922  if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3923  load_flags |= FT_LOAD_NO_BITMAP;
3924 
3925  if (iFormat & GGO_UNHINTED)
3926  {
3927  load_flags |= FT_LOAD_NO_HINTING;
3928  iFormat &= ~GGO_UNHINTED;
3929  }
3930 
3931  error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3932  if (error)
3933  {
3934  DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3936  if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3937  return GDI_ERROR;
3938  }
3940 
3941  FLOATOBJ_Set1(&widthRatio);
3942  if (aveWidth && potm)
3943  {
3944  // widthRatio = aveWidth * eM11 / potm->otmTextMetrics.tmAveCharWidth
3945  FLOATOBJ_SetLong(&widthRatio, aveWidth);
3946  FLOATOBJ_Mul(&widthRatio, &eM11);
3947  FLOATOBJ_DivLong(&widthRatio, potm->otmTextMetrics.tmAveCharWidth);
3948  }
3949 
3950  //left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3951  FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiBearingX);
3952  FLOATOBJ_Mul(&eTemp, &widthRatio);
3953  left = FLOATOBJ_GetLong(&eTemp) & -64;
3954 
3955  //right = (INT)((ft_face->glyph->metrics.horiBearingX +
3956  // ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3957  FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiBearingX * ft_face->glyph->metrics.width);
3958  FLOATOBJ_Mul(&eTemp, &widthRatio);
3959  FLOATOBJ_AddLong(&eTemp, 63);
3960  right = FLOATOBJ_GetLong(&eTemp) & -64;
3961 
3962  //adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3963  FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiAdvance);
3964  FLOATOBJ_Mul(&eTemp, &widthRatio);
3965  FLOATOBJ_AddLong(&eTemp, 63);
3966  adv = FLOATOBJ_GetLong(&eTemp) >> 6;
3967 
3968  lsb = left >> 6;
3969  bbx = (right - left) >> 6;
3970 
3971  DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3972 
3973  IntLockFreeType();
3974 
3975  /* Width scaling transform */
3976  if (!FLOATOBJ_Equal1(&widthRatio))
3977  {
3978  FT_Matrix scaleMat;
3979 
3980  eTemp = widthRatio;
3981  FLOATOBJ_MulLong(&eTemp, 1 << 16);
3982 
3983  scaleMat.xx = FLOATOBJ_GetLong(&eTemp);
3984  scaleMat.xy = 0;
3985  scaleMat.yx = 0;
3986  scaleMat.yy = INT_TO_FIXED(1);
3987  FT_Matrix_Multiply(&scaleMat, &transMat);
3988  needsTransform = TRUE;
3989  }
3990 
3991  /* World transform */
3992  {
3993  FT_Matrix ftmatrix;
3995 
3996  /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3997  FtMatrixFromMx(&ftmatrix, pmx);
3998 
3999  if (memcmp(&ftmatrix, &identityMat, sizeof(identityMat)) != 0)
4000  {
4001  FT_Matrix_Multiply(&ftmatrix, &transMat);
4002  needsTransform = TRUE;
4003  }
4004  }
4005 
4006  /* Rotation transform */
4007  if (orientation)
4008  {
4009  FT_Matrix rotationMat;
4010  DPRINT("Rotation Trans!\n");
4011  IntEscapeMatrix(&rotationMat, orientation);
4012  FT_Matrix_Multiply(&rotationMat, &transMat);
4013  needsTransform = TRUE;
4014  }
4015 
4016  /* Extra transformation specified by caller */
4017  if (pmat2)
4018  {
4019  FT_Matrix extraMat;
4020  DPRINT("MAT2 Matrix Trans!\n");
4021  extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
4022  extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
4023  extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
4024  extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
4025  FT_Matrix_Multiply(&extraMat, &transMat);
4026  needsTransform = TRUE;
4027  }
4028 
4029  if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
4030 
4031  if (!needsTransform)
4032  {
4033  DPRINT("No Need to be Transformed!\n");
4034  top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4035  bottom = (ft_face->glyph->metrics.horiBearingY -
4036  ft_face->glyph->metrics.height) & -64;
4037  gm.gmCellIncX = adv;
4038  gm.gmCellIncY = 0;
4039  }
4040  else
4041  {
4042  INT xc, yc;
4043  FT_Vector vec;
4044  for (xc = 0; xc < 2; xc++)
4045  {
4046  for (yc = 0; yc < 2; yc++)
4047  {
4048  vec.x = (ft_face->glyph->metrics.horiBearingX +
4049  xc * ft_face->glyph->metrics.width);
4050  vec.y = ft_face->glyph->metrics.horiBearingY -
4051  yc * ft_face->glyph->metrics.height;
4052  DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
4053  FT_Vector_Transform(&vec, &transMat);
4054  if (xc == 0 && yc == 0)
4055  {
4056  left = right = vec.x;
4057  top = bottom = vec.y;
4058  }
4059  else
4060  {
4061  if (vec.x < left) left = vec.x;
4062  else if (vec.x > right) right = vec.x;
4063  if (vec.y < bottom) bottom = vec.y;
4064  else if (vec.y > top) top = vec.y;
4065  }
4066  }
4067  }
4068  left = left & -64;
4069  right = (right + 63) & -64;
4070  bottom = bottom & -64;
4071  top = (top + 63) & -64;
4072 
4073  DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4074  vec.x = ft_face->glyph->metrics.horiAdvance;
4075  vec.y = 0;
4076  FT_Vector_Transform(&vec, &transMat);
4077  gm.gmCellIncX = (vec.x+63) >> 6;
4078  gm.gmCellIncY = -((vec.y+63) >> 6);
4079  }
4080  gm.gmBlackBoxX = (right - left) >> 6;
4081  gm.gmBlackBoxY = (top - bottom) >> 6;
4082  gm.gmptGlyphOrigin.x = left >> 6;
4083  gm.gmptGlyphOrigin.y = top >> 6;
4084 
4085  DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
4086  gm.gmCellIncX, gm.gmCellIncY,
4087  gm.gmBlackBoxX, gm.gmBlackBoxY,
4089 
4091 
4092 
4093  if (iFormat == GGO_METRICS)
4094  {
4095  DPRINT("GGO_METRICS Exit!\n");
4096  *pgm = gm;
4097  return 1; /* FIXME */
4098  }
4099 
4100  if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
4101  {
4102  DPRINT1("Loaded a bitmap\n");
4103  return GDI_ERROR;
4104  }
4105 
4106  switch (iFormat)
4107  {
4108  case GGO_BITMAP:
4109  {
4110  width = gm.gmBlackBoxX;
4111  height = gm.gmBlackBoxY;
4112  pitch = ((width + 31) >> 5) << 2;
4113  needed = pitch * height;
4114 
4115  if (!pvBuf || !cjBuf) break;
4116  if (!needed) return GDI_ERROR; /* empty glyph */
4117  if (needed > cjBuf)
4118  return GDI_ERROR;
4119 
4120  switch (ft_face->glyph->format)
4121  {
4123  {
4124  BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
4125  INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
4126  INT h = min( height, ft_face->glyph->bitmap.rows );
4127  while (h--)
4128  {
4129  RtlCopyMemory(dst, src, w);
4130  src += ft_face->glyph->bitmap.pitch;
4131  dst += pitch;
4132  }
4133  break;
4134  }
4135 
4137  {
4138  ft_bitmap.width = width;
4139  ft_bitmap.rows = height;
4140  ft_bitmap.pitch = pitch;
4141  ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
4142  ft_bitmap.buffer = pvBuf;
4143 
4144  IntLockFreeType();
4145  if (needsTransform)
4146  {
4147  FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4148  }
4149  FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4150  /* Note: FreeType will only set 'black' bits for us. */
4151  RtlZeroMemory(pvBuf, needed);
4152  FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
4154  break;
4155  }
4156 
4157  default:
4158  DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
4159  return GDI_ERROR;
4160  }
4161 
4162  break;
4163  }
4164 
4165  case GGO_GRAY2_BITMAP:
4166  case GGO_GRAY4_BITMAP:
4167  case GGO_GRAY8_BITMAP:
4168  {
4169  unsigned int mult, row, col;
4170  BYTE *start, *ptr;
4171 
4172  width = gm.gmBlackBoxX;
4173  height = gm.gmBlackBoxY;
4174  pitch = (width + 3) / 4 * 4;
4175  needed = pitch * height;
4176 
4177  if (!pvBuf || !cjBuf) break;
4178  if (!needed) return GDI_ERROR; /* empty glyph */
4179  if (needed > cjBuf)
4180  return GDI_ERROR;
4181 
4182  switch (ft_face->glyph->format)
4183  {
4185  {
4186  BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
4187  INT h = min( height, ft_face->glyph->bitmap.rows );
4188  INT x;
4189  while (h--)
4190  {
4191  for (x = 0; (UINT)x < pitch; x++)
4192  {
4193  if (x < ft_face->glyph->bitmap.width)
4194  dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4195  else
4196  dst[x] = 0;
4197  }
4198  src += ft_face->glyph->bitmap.pitch;
4199  dst += pitch;
4200  }
4201  break;
4202  }
4204  {
4205  ft_bitmap.width = width;
4206  ft_bitmap.rows = height;
4207  ft_bitmap.pitch = pitch;
4208  ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
4209  ft_bitmap.buffer = pvBuf;
4210 
4211  IntLockFreeType();
4212  if (needsTransform)
4213  {
4214  FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4215  }
4216  FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4217  RtlZeroMemory(ft_bitmap.buffer, cjBuf);
4218  FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
4220 
4221  if (iFormat == GGO_GRAY2_BITMAP)
4222  mult = 4;
4223  else if (iFormat == GGO_GRAY4_BITMAP)
4224  mult = 16;
4225  else if (iFormat == GGO_GRAY8_BITMAP)
4226  mult = 64;
4227  else
4228  {
4229  return GDI_ERROR;
4230  }
4231 
4232  start = pvBuf;
4233  for (row = 0; row < height; row++)
4234  {
4235  ptr = start;
4236  for (col = 0; col < width; col++, ptr++)
4237  {
4238  *ptr = (((int)*ptr) * mult + 128) / 256;
4239  }
4240  start += pitch;
4241  }
4242 
4243  break;
4244  }
4245  default:
4246  DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
4247  return GDI_ERROR;
4248  }
4249 
4250  break;
4251  }
4252 
4253  case GGO_NATIVE:
4254  {
4255  FT_Outline *outline = &ft_face->glyph->outline;
4256 
4257  if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
4258 
4259  IntLockFreeType();
4260  if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
4261 
4263 
4264  if (!pvBuf || !cjBuf)
4265  {
4267  break;
4268  }
4269  if (needed > cjBuf)
4270  {
4272  return GDI_ERROR;
4273  }
4276  break;
4277  }
4278 
4279  case GGO_BEZIER:
4280  {
4281  FT_Outline *outline = &ft_face->glyph->outline;
4282  if (cjBuf == 0) pvBuf = NULL;
4283 
4284  if (needsTransform && pvBuf)
4285  {
4286  IntLockFreeType();
4287  FT_Outline_Transform(outline, &transMat);
4289  }
4291 
4292  if (!pvBuf || !cjBuf)
4293  break;
4294  if (needed > cjBuf)
4295  return GDI_ERROR;
4296 
4298  break;
4299  }
4300 
4301  default:
4302  DPRINT1("Unsupported format %u\n", iFormat);
4303  return GDI_ERROR;
4304  }
4305 
4306  DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
4307  *pgm = gm;
4308  return needed;
4309 }
4310 
4311 BOOL
4312 FASTCALL
4314  PTEXTOBJ TextObj,
4315  LPCWSTR String,
4316  INT Count,
4317  ULONG MaxExtent,
4318  LPINT Fit,
4319  LPINT Dx,
4320  LPSIZE Size,
4321  FLONG fl)
4322 {
4323  PFONTGDI FontGDI;
4324  FT_Face face;
4325  FT_GlyphSlot glyph;
4326  FT_BitmapGlyph realglyph;
4327  INT error, glyph_index, i, previous;
4328  ULONGLONG TotalWidth64 = 0;
4329  BOOL use_kerning;
4330  FT_Render_Mode RenderMode;
4331  BOOLEAN Render;
4332  PMATRIX pmxWorldToDevice;
4333  LOGFONTW *plf;
4334  BOOL EmuBold, EmuItalic;
4335  LONG ascender, descender;
4336 
4337  FontGDI = ObjToGDI(TextObj->Font, FONT);
4338 
4339  face = FontGDI->SharedFace->Face;
4340  if (NULL != Fit)
4341  {
4342  *Fit = 0;
4343  }
4344 
4345  IntLockFreeType();
4346 
4347  TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
4348 
4349  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4350  EmuBold = EMUBOLD_NEEDED(FontGDI->OriginalWeight, plf->lfWeight);
4351  EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
4352 
4353  Render = IntIsFontRenderingEnabled();
4354  if (Render)
4355  RenderMode = IntGetFontRenderMode(plf);
4356  else
4357  RenderMode = FT_RENDER_MODE_MONO;
4358 
4359  /* Get the DC's world-to-device transformation matrix */
4360  pmxWorldToDevice = DC_pmxWorldToDevice(dc);
4361  FtSetCoordinateTransform(face, pmxWorldToDevice);
4362 
4363  use_kerning = FT_HAS_KERNING(face);
4364  previous = 0;
4365 
4366  for (i = 0; i < Count; i++)
4367  {
4368  glyph_index = get_glyph_index_flagged(face, *String, GTEF_INDICES, fl);
4369 
4370  if (EmuBold || EmuItalic)
4371  realglyph = NULL;
4372  else
4373  realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
4374  RenderMode, pmxWorldToDevice);
4375 
4376  if (EmuBold || EmuItalic || !realglyph)
4377  {
4378  if (EmuItalic)
4379  error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_BITMAP);
4380  else
4381  error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
4382  if (error)
4383  {
4384  DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
4385  break;
4386  }
4387 
4388  glyph = face->glyph;
4389  if (EmuBold || EmuItalic)
4390  {
4391  if (EmuBold)
4392  FT_GlyphSlot_Embolden(glyph);
4393  if (EmuItalic)
4394  FT_GlyphSlot_Oblique(glyph);
4395  realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
4396  }
4397  else
4398  {
4399  realglyph = ftGdiGlyphCacheSet(face,
4400  glyph_index,
4401  plf->lfHeight,
4402  pmxWorldToDevice,
4403  glyph,
4404  RenderMode);
4405  }
4406 
4407  if (!realglyph)
4408  {
4409  DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
4410  break;
4411  }
4412  }
4413 
4414  /* Retrieve kerning distance */
4415  if (use_kerning && previous && glyph_index)
4416  {
4417  FT_Vector delta;
4418  FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
4419  TotalWidth64 += delta.x;
4420  }
4421 
4422  TotalWidth64 += realglyph->root.advance.x >> 10;
4423 
4424  if (((TotalWidth64 + 32) >> 6) <= MaxExtent && NULL != Fit)
4425  {
4426  *Fit = i + 1;
4427  }
4428  if (NULL != Dx)
4429  {
4430  Dx[i] = (TotalWidth64 + 32) >> 6;
4431  }
4432 
4433  /* Bold and italic do not use the cache */
4434  if (EmuBold || EmuItalic)
4435  {
4436  FT_Done_Glyph((FT_Glyph)realglyph);
4437  }
4438 
4439  previous = glyph_index;
4440  String++;
4441  }
4442  ASSERT(FontGDI->Magic == FONTGDI_MAGIC);
4443  ascender = FontGDI->tmAscent; /* Units above baseline */
4444  descender = FontGDI->tmDescent; /* Units below baseline */
4446 
4447  Size->cx = (TotalWidth64 + 32) >> 6;
4448  Size->cy = ascender + descender;
4449 
4450  return TRUE;
4451 }
4452 
4453 
4454 INT
4455 FASTCALL
4457  PDC Dc,
4458  LPFONTSIGNATURE lpSig,
4459  DWORD dwFlags)
4460 {
4461  PDC_ATTR pdcattr;
4462  UINT Ret = DEFAULT_CHARSET;
4463  INT i;
4464  HFONT hFont;
4465  PTEXTOBJ TextObj;
4466  PFONTGDI FontGdi;
4467  FONTSIGNATURE fs;
4468  TT_OS2 *pOS2;
4469  FT_Face Face;
4470  CHARSETINFO csi;
4471  DWORD cp, fs0;
4472  USHORT usACP, usOEM;
4473 
4474  pdcattr = Dc->pdcattr;
4475  hFont = pdcattr->hlfntNew;
4476  TextObj = RealizeFontInit(hFont);
4477 
4478  if (!TextObj)
4479  {
4481  return Ret;
4482  }
4483  FontGdi = ObjToGDI(TextObj->Font, FONT);
4484  Face = FontGdi->SharedFace->Face;
4485  TEXTOBJ_UnlockText(TextObj);
4486 
4487  memset(&fs, 0, sizeof(FONTSIGNATURE));
4488  IntLockFreeType();
4489  pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4490  if (NULL != pOS2)
4491  {
4492  fs.fsCsb[0] = pOS2->ulCodePageRange1;
4493  fs.fsCsb[1] = pOS2->ulCodePageRange2;
4494  fs.fsUsb[0] = pOS2->ulUnicodeRange1;
4495  fs.fsUsb[1] = pOS2->ulUnicodeRange2;
4496  fs.fsUsb[2] = pOS2->ulUnicodeRange3;
4497  fs.fsUsb[3] = pOS2->ulUnicodeRange4;
4498  if (pOS2->version == 0)
4499  {
4500  FT_UInt dummy;
4501 
4502  if (FT_Get_First_Char( Face, &dummy ) < 0x100)
4503  fs.fsCsb[0] |= FS_LATIN1;
4504  else
4505  fs.fsCsb[0] |= FS_SYMBOL;
4506  }
4507  }
4508  pOS2 = NULL;
4510  DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
4511  if (fs.fsCsb[0] == 0)
4512  { /* Let's see if we can find any interesting cmaps */
4513  for (i = 0; i < Face->num_charmaps; i++)
4514  {
4515  switch (Face->charmaps[i]->encoding)
4516  {
4517  case FT_ENCODING_UNICODE:
4518  case FT_ENCODING_APPLE_ROMAN:
4519  fs.fsCsb[0] |= FS_LATIN1;
4520  break;
4521  case FT_ENCODING_MS_SYMBOL:
4522  fs.fsCsb[0] |= FS_SYMBOL;
4523  break;
4524  default:
4525  break;
4526  }
4527  }
4528  }
4529  if (lpSig)
4530  {
4531  RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
4532  }
4533 
4534  RtlGetDefaultCodePage(&usACP, &usOEM);
4535  cp = usACP;
4536 
4538  if (csi.fs.fsCsb[0] & fs.fsCsb[0])
4539  {
4540  DPRINT("Hit 1\n");
4541  Ret = csi.ciCharset;
4542  goto Exit;
4543  }
4544 
4545  for (i = 0; i < MAXTCIINDEX; i++)
4546  {
4547  fs0 = 1L << i;
4548  if (fs.fsCsb[0] & fs0)
4549  {
4550  if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
4551  {
4552  // *cp = csi.ciACP;
4553  DPRINT("Hit 2\n");
4554  Ret = csi.ciCharset;
4555  goto Exit;
4556  }
4557  else
4558  DPRINT1("TCI failing on %x\n", fs0);
4559  }
4560  }
4561 Exit:
4562  DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
4563  return (MAKELONG(csi.ciACP, csi.ciCharset));
4564 }
4565 
4566 
4567 DWORD
4568 FASTCALL
4570 {
4571  DWORD size = 0;
4572  DWORD num_ranges = 0;
4573  FT_Face face = Font->SharedFace->Face;
4574 
4575  if (face->charmap->encoding == FT_ENCODING_UNICODE)
4576  {
4577  FT_UInt glyph_code = 0;
4578  FT_ULong char_code, char_code_prev;
4579 
4580  char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
4581 
4582  DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4583  face->num_glyphs, glyph_code, char_code);
4584 
4585  if (!glyph_code) return 0;
4586 
4587  if (glyphset)
4588  {
4589  glyphset->ranges[0].wcLow = (USHORT)char_code;
4590  glyphset->ranges[0].cGlyphs = 0;
4591  glyphset->cGlyphsSupported = 0;
4592  }
4593 
4594  num_ranges = 1;
4595  while (glyph_code)
4596  {
4597  if (char_code < char_code_prev)
4598  {
4599  DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
4600  return 0;
4601  }
4602  if (char_code - char_code_prev > 1)
4603  {
4604  num_ranges++;
4605  if (glyphset)
4606  {
4607  glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4608  glyphset->ranges[num_ranges - 1].cGlyphs = 1;
4609  glyphset->cGlyphsSupported++;
4610  }
4611  }
4612  else if (glyphset)
4613  {
4614  glyphset->ranges[num_ranges - 1].cGlyphs++;
4615  glyphset->cGlyphsSupported++;
4616  }
4617  char_code_prev = char_code;
4618  char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
4619  }
4620  }
4621  else
4622  DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
4623 
4624  size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4625  if (glyphset)
4626  {
4627  glyphset->cbThis = size;
4628  glyphset->cRanges = num_ranges;
4629  glyphset->flAccel = 0;
4630  }
4631  return size;
4632 }
4633 
4634 
4635 BOOL
4636 FASTCALL
4638  HDC hDC,
4639  PTMW_INTERNAL ptmwi)
4640 {
4641  PDC dc;
4642  PDC_ATTR pdcattr;
4643  PTEXTOBJ TextObj;
4644  PFONTGDI FontGDI;
4645  FT_Face Face;
4646  TT_OS2 *pOS2;
4647  TT_HoriHeader *pHori;
4648  FT_WinFNT_HeaderRec Win;
4649  ULONG Error;
4651  LOGFONTW *plf;
4652 
4653  if (!ptmwi)
4654  {
4656  return FALSE;
4657  }
4658 
4659  if (!(dc = DC_LockDc(hDC)))
4660  {
4662  return FALSE;
4663  }
4664  pdcattr = dc->pdcattr;
4665  TextObj = RealizeFontInit(pdcattr->hlfntNew);
4666  if (NULL != TextObj)
4667  {
4668  plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4669  FontGDI = ObjToGDI(TextObj->Font, FONT);
4670 
4671  Face = FontGDI->SharedFace->Face;
4672 
4673  IntLockFreeType();
4674  Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
4677 
4678  if (0 != Error)
4679  {
4680  DPRINT1("Error in setting pixel sizes: %u\n", Error);
4682  }
4683  else
4684  {
4685  FT_Face Face = FontGDI->SharedFace->Face;
4687 
4688  IntLockFreeType();
4689  pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4690  if (NULL == pOS2)
4691  {
4692  DPRINT1("Can't find OS/2 table - not TT font?\n");
4694  }
4695 
4696  pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
4697  if (NULL == pHori)
4698  {
4699  DPRINT1("Can't find HHEA table - not TT font?\n");
4701  }
4702 
4703  Error = FT_Get_WinFNT_Header(Face, &Win);
4704 
4705  if (NT_SUCCESS(Status) || !Error)
4706  {
4707  FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
4708 
4709  /* FIXME: Fill Diff member */
4710  RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
4711  }
4712 
4714  }
4715  TEXTOBJ_UnlockText(TextObj);
4716  }
4717  else
4718  {
4720  }
4721  DC_UnlockDc(dc);
4722 
4723  if (!NT_SUCCESS(Status))
4724  {
4726  return FALSE;
4727  }
4728  return TRUE;
4729 }
4730 
4731 DWORD
4732 FASTCALL
4734  PFONTGDI FontGdi,
4735  DWORD Table,
4736  DWORD Offset,
4737  PVOID Buffer,
4738  DWORD Size)
4739 {
4741  FT_Face Face = FontGdi->SharedFace->Face;
4742 
4743  IntLockFreeType();
4744 
4745  if (FT_IS_SFNT(Face))
4746  {
4747  if (Table)
4748  Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |