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