f827edf87f3000418738ec6a729278ba27ebf0c1
[reactos.git] / reactos / win32ss / gdi / ntgdi / freetype.c
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-2017 Katayama Hirofumi MZ.
9 */
10
11 /** Includes ******************************************************************/
12
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
35 #define NDEBUG
36 #include <debug.h>
37
38 /* TPMF_FIXED_PITCH is confusing; brain-dead api */
39 #ifndef _TMPF_VARIABLE_PITCH
40 #define _TMPF_VARIABLE_PITCH TMPF_FIXED_PITCH
41 #endif
42
43 extern const MATRIX gmxWorldToDeviceDefault;
44 extern const MATRIX gmxWorldToPageDefault;
45
46 /* HACK!! Fix XFORMOBJ then use 1:16 / 16:1 */
47 #define gmxWorldToDeviceDefault gmxWorldToPageDefault
48
49 FT_Library library;
50
51 /* special font names */
52 static const UNICODE_STRING MarlettW = RTL_CONSTANT_STRING(L"Marlett");
53 static const UNICODE_STRING SystemW = RTL_CONSTANT_STRING(L"System");
54 static const UNICODE_STRING FixedSysW = RTL_CONSTANT_STRING(L"FixedSys");
55
56 /* registry */
57 static UNICODE_STRING FontRegPath =
58 RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
59
60 static PSHARED_FACE
61 SharedFace_Create(FT_Face Face)
62 {
63 PSHARED_FACE Ptr;
64 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
65 if (Ptr)
66 {
67 Ptr->Face = Face;
68 Ptr->RefCount = 1;
69 }
70 return Ptr;
71 }
72
73 static void
74 SharedFace_AddRef(PSHARED_FACE Ptr)
75 {
76 ++Ptr->RefCount;
77 }
78
79 static void
80 SharedFace_Release(PSHARED_FACE Ptr)
81 {
82 if (Ptr->RefCount <= 0)
83 return;
84
85 --Ptr->RefCount;
86 if (Ptr->RefCount == 0)
87 {
88 FT_Done_Face(Ptr->Face);
89 ExFreePoolWithTag(Ptr, TAG_FONT);
90 }
91 }
92
93 typedef struct _FONT_ENTRY
94 {
95 LIST_ENTRY ListEntry;
96 FONTGDI *Font;
97 UNICODE_STRING FaceName;
98 BYTE NotEnum;
99 } FONT_ENTRY, *PFONT_ENTRY;
100
101 /* The FreeType library is not thread safe, so we have
102 to serialize access to it */
103 static PFAST_MUTEX FreeTypeLock;
104
105 static LIST_ENTRY FontListHead;
106 static PFAST_MUTEX FontListLock;
107 static BOOL RenderingEnabled = TRUE;
108
109 #define IntLockGlobalFonts \
110 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FontListLock)
111
112 #define IntUnLockGlobalFonts \
113 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
114
115 #define IntLockFreeType \
116 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
117
118 #define IntUnLockFreeType \
119 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock)
120
121 #define MAX_FONT_CACHE 256
122
123 typedef struct _FONT_CACHE_ENTRY
124 {
125 LIST_ENTRY ListEntry;
126 int GlyphIndex;
127 FT_Face Face;
128 FT_BitmapGlyph BitmapGlyph;
129 int Height;
130 MATRIX mxWorldToDevice;
131 } FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY;
132 static LIST_ENTRY FontCacheListHead;
133 static UINT FontCacheNumEntries;
134
135 static PWCHAR ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */
136 {
137 L"Western", /* 00 */
138 L"Central_European",
139 L"Cyrillic",
140 L"Greek",
141 L"Turkish",
142 L"Hebrew",
143 L"Arabic",
144 L"Baltic",
145 L"Vietnamese", /* 08 */
146 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */
147 L"Thai",
148 L"Japanese",
149 L"CHINESE_GB2312",
150 L"Hangul",
151 L"CHINESE_BIG5",
152 L"Hangul(Johab)",
153 NULL, NULL, /* 23 */
154 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
155 L"Symbol" /* 31 */
156 };
157
158 /*
159 * For TranslateCharsetInfo
160 */
161 #define CP_SYMBOL 42
162 #define MAXTCIINDEX 32
163 static const CHARSETINFO FontTci[MAXTCIINDEX] =
164 {
165 /* ANSI */
166 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
167 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
168 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
169 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
170 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
171 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
172 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
173 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
174 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
175 /* reserved by ANSI */
176 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
177 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
178 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
179 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
180 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
181 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
182 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
183 /* ANSI and OEM */
184 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
185 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
186 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
187 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
188 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
189 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
190 /* Reserved for alternate ANSI and OEM */
191 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
192 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
193 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
194 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
195 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
196 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
197 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
198 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
199 /* Reserved for system */
200 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
201 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
202 };
203
204 /*
205 * FONTSUBST_... --- constants for font substitutes
206 */
207 #define FONTSUBST_FROM 0
208 #define FONTSUBST_TO 1
209 #define FONTSUBST_FROM_AND_TO 2
210
211 /*
212 * FONTSUBST_ENTRY --- font substitute entry
213 */
214 typedef struct FONTSUBST_ENTRY
215 {
216 LIST_ENTRY ListEntry;
217 UNICODE_STRING FontNames[FONTSUBST_FROM_AND_TO];
218 BYTE CharSets[FONTSUBST_FROM_AND_TO];
219 } FONTSUBST_ENTRY, *PFONTSUBST_ENTRY;
220
221 /* list head */
222 static RTL_STATIC_LIST_HEAD(FontSubstListHead);
223
224 /*
225 * IntLoadFontSubstList --- loads the list of font substitutes
226 */
227 BOOL FASTCALL
228 IntLoadFontSubstList(PLIST_ENTRY pHead)
229 {
230 NTSTATUS Status;
231 HANDLE KeyHandle;
232 OBJECT_ATTRIBUTES ObjectAttributes;
233 KEY_FULL_INFORMATION KeyFullInfo;
234 ULONG i, Length;
235 UNICODE_STRING FromW, ToW;
236 BYTE InfoBuffer[128];
237 PKEY_VALUE_FULL_INFORMATION pInfo;
238 BYTE CharSets[FONTSUBST_FROM_AND_TO];
239 LPWSTR pch;
240 PFONTSUBST_ENTRY pEntry;
241
242 /* the FontSubstitutes registry key */
243 static UNICODE_STRING FontSubstKey =
244 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\"
245 L"Microsoft\\Windows NT\\CurrentVersion\\"
246 L"FontSubstitutes");
247
248 /* open registry key */
249 InitializeObjectAttributes(&ObjectAttributes, &FontSubstKey,
250 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
251 NULL, NULL);
252 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
253 if (!NT_SUCCESS(Status))
254 {
255 DPRINT("ZwOpenKey failed: 0x%08X\n", Status);
256 return FALSE; /* failure */
257 }
258
259 /* query count of values */
260 Status = ZwQueryKey(KeyHandle, KeyFullInformation,
261 &KeyFullInfo, sizeof(KeyFullInfo), &Length);
262 if (!NT_SUCCESS(Status))
263 {
264 DPRINT("ZwQueryKey failed: 0x%08X\n", Status);
265 ZwClose(KeyHandle);
266 return FALSE; /* failure */
267 }
268
269 /* for each value */
270 for (i = 0; i < KeyFullInfo.Values; ++i)
271 {
272 /* get value name */
273 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
274 InfoBuffer, sizeof(InfoBuffer), &Length);
275 if (!NT_SUCCESS(Status))
276 {
277 DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status);
278 break; /* failure */
279 }
280
281 /* create FromW string */
282 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
283 Length = pInfo->NameLength / sizeof(WCHAR);
284 pInfo->Name[Length] = UNICODE_NULL; /* truncate */
285 Status = RtlCreateUnicodeString(&FromW, pInfo->Name);
286 if (!NT_SUCCESS(Status))
287 {
288 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
289 break; /* failure */
290 }
291
292 /* query value */
293 Status = ZwQueryValueKey(KeyHandle, &FromW, KeyValueFullInformation,
294 InfoBuffer, sizeof(InfoBuffer), &Length);
295 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
296 if (!NT_SUCCESS(Status) || !pInfo->DataLength)
297 {
298 DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status);
299 RtlFreeUnicodeString(&FromW);
300 break; /* failure */
301 }
302
303 /* create ToW string */
304 pch = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
305 Length = pInfo->DataLength / sizeof(WCHAR);
306 pch[Length] = UNICODE_NULL; /* truncate */
307 Status = RtlCreateUnicodeString(&ToW, pch);
308 if (!NT_SUCCESS(Status))
309 {
310 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
311 RtlFreeUnicodeString(&FromW);
312 break; /* failure */
313 }
314
315 /* does charset exist? (from) */
316 CharSets[FONTSUBST_FROM] = DEFAULT_CHARSET;
317 pch = wcsrchr(FromW.Buffer, L',');
318 if (pch)
319 {
320 /* truncate */
321 *pch = UNICODE_NULL;
322 FromW.Length = (pch - FromW.Buffer) * sizeof(WCHAR);
323 /* parse charset number */
324 CharSets[FONTSUBST_FROM] = (BYTE)_wtoi(pch + 1);
325 }
326
327 /* does charset exist? (to) */
328 CharSets[FONTSUBST_TO] = DEFAULT_CHARSET;
329 pch = wcsrchr(ToW.Buffer, L',');
330 if (pch)
331 {
332 /* truncate */
333 *pch = UNICODE_NULL;
334 ToW.Length = (pch - ToW.Buffer) * sizeof(WCHAR);
335 /* parse charset number */
336 CharSets[FONTSUBST_TO] = (BYTE)_wtoi(pch + 1);
337 }
338
339 /* allocate an entry */
340 pEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONTSUBST_ENTRY), TAG_FONT);
341 if (pEntry == NULL)
342 {
343 DPRINT("ExAllocatePoolWithTag failed\n");
344 RtlFreeUnicodeString(&FromW);
345 RtlFreeUnicodeString(&ToW);
346 break; /* failure */
347 }
348
349 /* store to *pEntry */
350 pEntry->FontNames[FONTSUBST_FROM] = FromW;
351 pEntry->FontNames[FONTSUBST_TO] = ToW;
352 pEntry->CharSets[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
353 pEntry->CharSets[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
354
355 /* insert pEntry to *pHead */
356 InsertTailList(pHead, &pEntry->ListEntry);
357 }
358
359 /* close now */
360 ZwClose(KeyHandle);
361
362 return NT_SUCCESS(Status);
363 }
364
365 BOOL FASTCALL
366 InitFontSupport(VOID)
367 {
368 ULONG ulError;
369
370 InitializeListHead(&FontListHead);
371 InitializeListHead(&FontCacheListHead);
372 FontCacheNumEntries = 0;
373 /* Fast Mutexes must be allocated from non paged pool */
374 FontListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
375 if (FontListLock == NULL)
376 {
377 return FALSE;
378 }
379
380 ExInitializeFastMutex(FontListLock);
381 FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
382 if (FreeTypeLock == NULL)
383 {
384 return FALSE;
385 }
386 ExInitializeFastMutex(FreeTypeLock);
387
388 ulError = FT_Init_FreeType(&library);
389 if (ulError)
390 {
391 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
392 return FALSE;
393 }
394
395 IntLoadSystemFonts();
396 IntLoadFontSubstList(&FontSubstListHead);
397
398 return TRUE;
399 }
400
401 VOID
402 FtSetCoordinateTransform(
403 FT_Face face,
404 PMATRIX pmx)
405 {
406 FT_Matrix ftmatrix;
407 FLOATOBJ efTemp;
408
409 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
410 efTemp = pmx->efM11;
411 FLOATOBJ_MulLong(&efTemp, 0x00010000);
412 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
413
414 efTemp = pmx->efM12;
415 FLOATOBJ_MulLong(&efTemp, 0x00010000);
416 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
417
418 efTemp = pmx->efM21;
419 FLOATOBJ_MulLong(&efTemp, 0x00010000);
420 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
421
422 efTemp = pmx->efM22;
423 FLOATOBJ_MulLong(&efTemp, 0x00010000);
424 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
425
426 /* Set the transformation matrix */
427 FT_Set_Transform(face, &ftmatrix, 0);
428 }
429
430 static BOOL
431 SubstituteFontByList(PLIST_ENTRY pHead,
432 PUNICODE_STRING pOutputName,
433 PUNICODE_STRING pInputName,
434 BYTE RequestedCharSet,
435 BYTE CharSetMap[FONTSUBST_FROM_AND_TO])
436 {
437 NTSTATUS Status;
438 PLIST_ENTRY pListEntry;
439 PFONTSUBST_ENTRY pSubstEntry;
440 BYTE CharSets[FONTSUBST_FROM_AND_TO];
441
442 CharSetMap[FONTSUBST_FROM] = DEFAULT_CHARSET;
443 CharSetMap[FONTSUBST_TO] = RequestedCharSet;
444
445 /* for each list entry */
446 for (pListEntry = pHead->Flink;
447 pListEntry != pHead;
448 pListEntry = pListEntry->Flink)
449 {
450 pSubstEntry =
451 (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_ENTRY, ListEntry);
452
453 CharSets[FONTSUBST_FROM] = pSubstEntry->CharSets[FONTSUBST_FROM];
454
455 if (CharSets[FONTSUBST_FROM] != DEFAULT_CHARSET &&
456 CharSets[FONTSUBST_FROM] != RequestedCharSet)
457 {
458 continue; /* not matched */
459 }
460
461 /* does charset number exist? (to) */
462 if (pSubstEntry->CharSets[FONTSUBST_TO] != DEFAULT_CHARSET)
463 {
464 CharSets[FONTSUBST_TO] = pSubstEntry->CharSets[FONTSUBST_TO];
465 }
466 else
467 {
468 CharSets[FONTSUBST_TO] = RequestedCharSet;
469 }
470
471 /* does font name match? */
472 if (!RtlEqualUnicodeString(&pSubstEntry->FontNames[FONTSUBST_FROM],
473 pInputName, TRUE))
474 {
475 continue; /* not matched */
476 }
477
478 /* update *pOutputName */
479 RtlFreeUnicodeString(pOutputName);
480 Status = RtlCreateUnicodeString(pOutputName,
481 pSubstEntry->FontNames[FONTSUBST_TO].Buffer);
482 if (!NT_SUCCESS(Status))
483 {
484 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
485 continue; /* cannot create string */
486 }
487
488 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
489 {
490 /* update CharSetMap */
491 CharSetMap[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
492 CharSetMap[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
493 }
494 return TRUE; /* success */
495 }
496
497 return FALSE;
498 }
499
500 static BOOL
501 SubstituteFontRecurse(PUNICODE_STRING pInOutName, BYTE *pRequestedCharSet)
502 {
503 UINT RecurseCount = 5;
504 UNICODE_STRING OutputNameW = { 0 };
505 BYTE CharSetMap[FONTSUBST_FROM_AND_TO];
506 BOOL Found;
507
508 if (pInOutName->Buffer[0] == UNICODE_NULL)
509 return FALSE;
510
511 while (RecurseCount-- > 0)
512 {
513 RtlInitUnicodeString(&OutputNameW, NULL);
514 Found = SubstituteFontByList(&FontSubstListHead,
515 &OutputNameW, pInOutName,
516 *pRequestedCharSet, CharSetMap);
517 if (!Found)
518 break;
519
520 /* update *pInOutName and *pRequestedCharSet */
521 RtlFreeUnicodeString(pInOutName);
522 *pInOutName = OutputNameW;
523 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
524 CharSetMap[FONTSUBST_FROM] == *pRequestedCharSet)
525 {
526 *pRequestedCharSet = CharSetMap[FONTSUBST_TO];
527 }
528 }
529
530 return TRUE; /* success */
531 }
532
533 /*
534 * IntLoadSystemFonts
535 *
536 * Search the system font directory and adds each font found.
537 */
538 VOID FASTCALL
539 IntLoadSystemFonts(VOID)
540 {
541 OBJECT_ATTRIBUTES ObjectAttributes;
542 UNICODE_STRING Directory, FileName, TempString;
543 IO_STATUS_BLOCK Iosb;
544 HANDLE hDirectory;
545 BYTE *DirInfoBuffer;
546 PFILE_DIRECTORY_INFORMATION DirInfo;
547 BOOLEAN bRestartScan = TRUE;
548 NTSTATUS Status;
549 INT i;
550 static UNICODE_STRING SearchPatterns[] =
551 {
552 RTL_CONSTANT_STRING(L"*.ttf"),
553 RTL_CONSTANT_STRING(L"*.ttc"),
554 RTL_CONSTANT_STRING(L"*.otf"),
555 RTL_CONSTANT_STRING(L"*.otc"),
556 RTL_CONSTANT_STRING(L"*.fon"),
557 RTL_CONSTANT_STRING(L"*.fnt")
558 };
559
560 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
561
562 InitializeObjectAttributes(
563 &ObjectAttributes,
564 &Directory,
565 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
566 NULL,
567 NULL);
568
569 Status = ZwOpenFile(
570 &hDirectory,
571 SYNCHRONIZE | FILE_LIST_DIRECTORY,
572 &ObjectAttributes,
573 &Iosb,
574 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
575 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
576
577 if (NT_SUCCESS(Status))
578 {
579 for (i = 0; i < _countof(SearchPatterns); ++i)
580 {
581 DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
582 if (DirInfoBuffer == NULL)
583 {
584 ZwClose(hDirectory);
585 return;
586 }
587
588 FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
589 if (FileName.Buffer == NULL)
590 {
591 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
592 ZwClose(hDirectory);
593 return;
594 }
595 FileName.Length = 0;
596 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
597
598 while (1)
599 {
600 Status = ZwQueryDirectoryFile(
601 hDirectory,
602 NULL,
603 NULL,
604 NULL,
605 &Iosb,
606 DirInfoBuffer,
607 0x4000,
608 FileDirectoryInformation,
609 FALSE,
610 &SearchPatterns[i],
611 bRestartScan);
612
613 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
614 {
615 break;
616 }
617
618 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
619 while (1)
620 {
621 TempString.Buffer = DirInfo->FileName;
622 TempString.Length =
623 TempString.MaximumLength = DirInfo->FileNameLength;
624 RtlCopyUnicodeString(&FileName, &Directory);
625 RtlAppendUnicodeStringToString(&FileName, &TempString);
626 IntGdiAddFontResource(&FileName, 0);
627 if (DirInfo->NextEntryOffset == 0)
628 break;
629 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
630 }
631
632 bRestartScan = FALSE;
633 }
634
635 ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
636 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
637 }
638 ZwClose(hDirectory);
639 }
640 }
641
642 static BYTE
643 ItalicFromStyle(const char *style_name)
644 {
645 if (style_name == NULL || style_name[0] == 0)
646 return FALSE;
647 if (strstr(style_name, "Italic") != NULL)
648 return TRUE;
649 if (strstr(style_name, "Oblique") != NULL)
650 return TRUE;
651 return FALSE;
652 }
653
654 static LONG
655 WeightFromStyle(const char *style_name)
656 {
657 if (style_name == NULL || style_name[0] == 0)
658 return FW_NORMAL;
659 if (strstr(style_name, "Regular") != NULL)
660 return FW_REGULAR;
661 if (strstr(style_name, "Normal") != NULL)
662 return FW_NORMAL;
663 if (strstr(style_name, "SemiBold") != NULL)
664 return FW_SEMIBOLD;
665 if (strstr(style_name, "UltraBold") != NULL)
666 return FW_ULTRABOLD;
667 if (strstr(style_name, "DemiBold") != NULL)
668 return FW_DEMIBOLD;
669 if (strstr(style_name, "ExtraBold") != NULL)
670 return FW_EXTRABOLD;
671 if (strstr(style_name, "Bold") != NULL)
672 return FW_BOLD;
673 if (strstr(style_name, "UltraLight") != NULL)
674 return FW_ULTRALIGHT;
675 if (strstr(style_name, "ExtraLight") != NULL)
676 return FW_EXTRALIGHT;
677 if (strstr(style_name, "Light") != NULL)
678 return FW_LIGHT;
679 if (strstr(style_name, "Hairline") != NULL)
680 return 50;
681 if (strstr(style_name, "Book") != NULL)
682 return 350;
683 if (strstr(style_name, "ExtraBlack") != NULL)
684 return 950;
685 if (strstr(style_name, "UltraBlack") != NULL)
686 return 1000;
687 if (strstr(style_name, "Black") != NULL)
688 return FW_BLACK;
689 if (strstr(style_name, "Medium") != NULL)
690 return FW_MEDIUM;
691 if (strstr(style_name, "Thin") != NULL)
692 return FW_THIN;
693 if (strstr(style_name, "Heavy") != NULL)
694 return FW_HEAVY;
695 return FW_NORMAL;
696 }
697
698 typedef struct GDI_LOAD_FONT
699 {
700 PUNICODE_STRING pFileName;
701 PVOID Buffer;
702 ULONG BufferSize;
703 DWORD Characteristics;
704 UNICODE_STRING RegValueName;
705 BOOL IsTrueType;
706 } GDI_LOAD_FONT, *PGDI_LOAD_FONT;
707
708 static INT FASTCALL
709 IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
710 PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
711 {
712 FT_Error Error;
713 PFONT_ENTRY Entry;
714 FONTGDI * FontGDI;
715 NTSTATUS Status;
716 FT_Face Face;
717 ANSI_STRING AnsiFaceName;
718 FT_WinFNT_HeaderRec WinFNT;
719 INT FontCount = 0, CharSetCount = 0;
720 PUNICODE_STRING pFileName = pLoadFont->pFileName;
721 PVOID Buffer = pLoadFont->Buffer;
722 ULONG BufferSize = pLoadFont->BufferSize;
723 DWORD Characteristics = pLoadFont->Characteristics;
724 PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
725 TT_OS2 * pOS2;
726 INT BitIndex;
727 FT_UShort os2_version;
728 FT_ULong os2_ulCodePageRange1;
729 FT_UShort os2_usWeightClass;
730
731 if (SharedFace == NULL && CharSetIndex == -1)
732 {
733 /* load a face from memory */
734 IntLockFreeType;
735 Error = FT_New_Memory_Face(
736 library,
737 Buffer,
738 BufferSize,
739 ((FontIndex != -1) ? FontIndex : 0),
740 &Face);
741 IntUnLockFreeType;
742
743 if (FT_IS_SFNT(Face))
744 pLoadFont->IsTrueType = TRUE;
745
746 if (!Error)
747 SharedFace = SharedFace_Create(Face);
748 if (Error || SharedFace == NULL)
749 {
750 if (Error == FT_Err_Unknown_File_Format)
751 DPRINT1("Unknown font file format\n");
752 else
753 DPRINT1("Error reading font file (error code: %d)\n", Error);
754 return 0; /* failure */
755 }
756 }
757 else
758 {
759 Face = SharedFace->Face;
760 SharedFace_AddRef(SharedFace);
761 }
762
763 /* allocate a FONT_ENTRY */
764 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
765 if (!Entry)
766 {
767 SharedFace_Release(SharedFace);
768 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
769 return 0; /* failure */
770 }
771
772 /* allocate a FONTGDI */
773 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
774 if (!FontGDI)
775 {
776 SharedFace_Release(SharedFace);
777 ExFreePoolWithTag(Entry, TAG_FONT);
778 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
779 return 0; /* failure */
780 }
781
782 /* set file name */
783 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool,
784 pFileName->Length + sizeof(UNICODE_NULL),
785 GDITAG_PFF);
786 if (FontGDI->Filename == NULL)
787 {
788 EngFreeMem(FontGDI);
789 SharedFace_Release(SharedFace);
790 ExFreePoolWithTag(Entry, TAG_FONT);
791 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
792 return 0; /* failure */
793 }
794 RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
795 FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
796
797 /* set face */
798 FontGDI->SharedFace = SharedFace;
799 FontGDI->CharSet = ANSI_CHARSET;
800 FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name);
801 FontGDI->RequestItalic = FALSE;
802 FontGDI->OriginalWeight = WeightFromStyle(Face->style_name);
803 FontGDI->RequestWeight = FW_NORMAL;
804
805 RtlInitAnsiString(&AnsiFaceName, Face->family_name);
806 Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
807 if (!NT_SUCCESS(Status))
808 {
809 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
810 EngFreeMem(FontGDI);
811 SharedFace_Release(SharedFace);
812 ExFreePoolWithTag(Entry, TAG_FONT);
813 return 0;
814 }
815
816 os2_version = 0;
817 IntLockFreeType;
818 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
819 if (pOS2)
820 {
821 os2_version = pOS2->version;
822 os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
823 os2_usWeightClass = pOS2->usWeightClass;
824 }
825 IntUnLockFreeType;
826
827 if (pOS2 && os2_version >= 1)
828 {
829 /* get charset and weight from OS/2 header */
830
831 /* Make sure we do not use this pointer anymore */
832 pOS2 = NULL;
833
834 for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
835 {
836 if (os2_ulCodePageRange1 & (1 << BitIndex))
837 {
838 if (FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
839 continue;
840
841 if ((CharSetIndex == -1 && CharSetCount == 0) ||
842 CharSetIndex == CharSetCount)
843 {
844 FontGDI->CharSet = FontTci[BitIndex].ciCharset;
845 }
846
847 ++CharSetCount;
848 }
849 }
850
851 /* set actual weight */
852 FontGDI->OriginalWeight = os2_usWeightClass;
853 }
854 else
855 {
856 /* get charset from WinFNT header */
857 IntLockFreeType;
858 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
859 if (!Error)
860 {
861 FontGDI->CharSet = WinFNT.charset;
862 }
863 IntUnLockFreeType;
864 }
865
866 /* FIXME: CharSet is invalid on Marlett */
867 if (RtlEqualUnicodeString(&Entry->FaceName, &MarlettW, TRUE))
868 {
869 FontGDI->CharSet = SYMBOL_CHARSET;
870 }
871
872 ++FontCount;
873 DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
874 DPRINT("Num glyphs: %d\n", Face->num_glyphs);
875 DPRINT("CharSet: %d\n", FontGDI->CharSet);
876
877 /* Add this font resource to the font table */
878 Entry->Font = FontGDI;
879 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
880
881 if (Characteristics & FR_PRIVATE)
882 {
883 /* private font */
884 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
885 IntLockProcessPrivateFonts(Win32Process);
886 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
887 IntUnLockProcessPrivateFonts(Win32Process);
888 }
889 else
890 {
891 /* global font */
892 IntLockGlobalFonts;
893 InsertTailList(&FontListHead, &Entry->ListEntry);
894 IntUnLockGlobalFonts;
895 }
896
897 if (FontIndex == -1)
898 {
899 if (FT_IS_SFNT(Face))
900 {
901 TT_Face TrueType = (TT_Face)Face;
902 if (TrueType->ttc_header.count > 1)
903 {
904 FT_Long i;
905 for (i = 1; i < TrueType->ttc_header.count; ++i)
906 {
907 FontCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
908 }
909 }
910 }
911 FontIndex = 0;
912 }
913
914 if (CharSetIndex == -1)
915 {
916 INT i;
917
918 if (pLoadFont->RegValueName.Length == 0)
919 {
920 RtlCreateUnicodeString(pValueName, Entry->FaceName.Buffer);
921 }
922 else
923 {
924 UNICODE_STRING NewString;
925 USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + Entry->FaceName.Length;
926 NewString.Length = 0;
927 NewString.MaximumLength = Length + sizeof(WCHAR);
928 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
929 NewString.MaximumLength,
930 TAG_USTR);
931 NewString.Buffer[0] = UNICODE_NULL;
932
933 RtlAppendUnicodeStringToString(&NewString, pValueName);
934 RtlAppendUnicodeToString(&NewString, L" & ");
935 RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
936
937 RtlFreeUnicodeString(pValueName);
938 *pValueName = NewString;
939 }
940
941 for (i = 1; i < CharSetCount; ++i)
942 {
943 FontCount += IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
944 }
945 }
946
947 return FontCount; /* number of loaded fonts */
948 }
949
950 /*
951 * IntGdiAddFontResource
952 *
953 * Adds the font resource from the specified file to the system.
954 */
955
956 INT FASTCALL
957 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
958 {
959 NTSTATUS Status;
960 HANDLE FileHandle;
961 PVOID Buffer = NULL;
962 IO_STATUS_BLOCK Iosb;
963 PVOID SectionObject;
964 ULONG ViewSize = 0;
965 LARGE_INTEGER SectionSize;
966 OBJECT_ATTRIBUTES ObjectAttributes;
967 GDI_LOAD_FONT LoadFont;
968 INT FontCount;
969 HANDLE KeyHandle;
970 static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
971
972 /* Open the font file */
973 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
974 Status = ZwOpenFile(
975 &FileHandle,
976 FILE_GENERIC_READ | SYNCHRONIZE,
977 &ObjectAttributes,
978 &Iosb,
979 FILE_SHARE_READ,
980 FILE_SYNCHRONOUS_IO_NONALERT);
981 if (!NT_SUCCESS(Status))
982 {
983 DPRINT("Could not load font file: %wZ\n", FileName);
984 return 0;
985 }
986
987 SectionSize.QuadPart = 0LL;
988 Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
989 NULL, &SectionSize, PAGE_READONLY,
990 SEC_COMMIT, FileHandle, NULL);
991 if (!NT_SUCCESS(Status))
992 {
993 DPRINT("Could not map file: %wZ\n", FileName);
994 ZwClose(FileHandle);
995 return 0;
996 }
997 ZwClose(FileHandle);
998
999 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
1000 if (!NT_SUCCESS(Status))
1001 {
1002 DPRINT("Could not map file: %wZ\n", FileName);
1003 ObDereferenceObject(SectionObject);
1004 return 0;
1005 }
1006
1007 LoadFont.pFileName = FileName;
1008 LoadFont.Buffer = Buffer;
1009 LoadFont.BufferSize = ViewSize;
1010 LoadFont.Characteristics = Characteristics;
1011 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1012 LoadFont.IsTrueType = FALSE;
1013 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1014
1015 ObDereferenceObject(SectionObject);
1016
1017 if (FontCount > 0)
1018 {
1019 if (LoadFont.IsTrueType)
1020 {
1021 /* append " (TrueType)" */
1022 UNICODE_STRING NewString;
1023 USHORT Length;
1024
1025 Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length;
1026 NewString.Length = 0;
1027 NewString.MaximumLength = Length + sizeof(WCHAR);
1028 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1029 NewString.MaximumLength,
1030 TAG_USTR);
1031 NewString.Buffer[0] = UNICODE_NULL;
1032
1033 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
1034 RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
1035 RtlFreeUnicodeString(&LoadFont.RegValueName);
1036 LoadFont.RegValueName = NewString;
1037 }
1038
1039 /* registry */
1040 InitializeObjectAttributes(&ObjectAttributes, &FontRegPath,
1041 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1042 NULL, NULL);
1043 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
1044 if (NT_SUCCESS(Status))
1045 {
1046 ULONG DataSize;
1047 LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
1048 if (pFileName)
1049 {
1050 pFileName++;
1051 DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
1052 ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
1053 pFileName, DataSize);
1054 }
1055 ZwClose(KeyHandle);
1056 }
1057 }
1058 RtlFreeUnicodeString(&LoadFont.RegValueName);
1059
1060 return FontCount;
1061 }
1062
1063 // FIXME: Add RemoveFontResource
1064
1065 BOOL FASTCALL
1066 IntIsFontRenderingEnabled(VOID)
1067 {
1068 BOOL Ret = RenderingEnabled;
1069 HDC hDC;
1070
1071 hDC = IntGetScreenDC();
1072 if (hDC)
1073 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
1074
1075 return Ret;
1076 }
1077
1078 VOID FASTCALL
1079 IntEnableFontRendering(BOOL Enable)
1080 {
1081 RenderingEnabled = Enable;
1082 }
1083
1084 FT_Render_Mode FASTCALL
1085 IntGetFontRenderMode(LOGFONTW *logfont)
1086 {
1087 switch (logfont->lfQuality)
1088 {
1089 case ANTIALIASED_QUALITY:
1090 case NONANTIALIASED_QUALITY:
1091 return FT_RENDER_MODE_MONO;
1092 case DRAFT_QUALITY:
1093 return FT_RENDER_MODE_LIGHT;
1094 /* case CLEARTYPE_QUALITY:
1095 return FT_RENDER_MODE_LCD; */
1096 }
1097 return FT_RENDER_MODE_NORMAL;
1098 }
1099
1100
1101 NTSTATUS FASTCALL
1102 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
1103 {
1104 PLFONT plfont;
1105 LOGFONTW *plf;
1106
1107 plfont = LFONT_AllocFontWithHandle();
1108 if (!plfont)
1109 {
1110 return STATUS_NO_MEMORY;
1111 }
1112
1113 ExInitializePushLock(&plfont->lock);
1114 *NewFont = plfont->BaseObject.hHmgr;
1115 plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
1116 RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
1117 if (lf->lfEscapement != lf->lfOrientation)
1118 {
1119 /* This should really depend on whether GM_ADVANCED is set */
1120 plf->lfOrientation = plf->lfEscapement;
1121 }
1122 LFONT_UnlockFont(plfont);
1123
1124 return STATUS_SUCCESS;
1125 }
1126
1127 /*************************************************************************
1128 * TranslateCharsetInfo
1129 *
1130 * Fills a CHARSETINFO structure for a character set, code page, or
1131 * font. This allows making the correspondance between different labelings
1132 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
1133 * of the same encoding.
1134 *
1135 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
1136 * only one codepage should be set in *Src.
1137 *
1138 * RETURNS
1139 * TRUE on success, FALSE on failure.
1140 *
1141 */
1142 static BOOLEAN APIENTRY
1143 IntTranslateCharsetInfo(PDWORD Src, /* [in]
1144 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
1145 if flags == TCI_SRCCHARSET: a character set value
1146 if flags == TCI_SRCCODEPAGE: a code page value */
1147 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
1148 DWORD Flags /* [in] determines interpretation of lpSrc */)
1149 {
1150 int Index = 0;
1151
1152 switch (Flags)
1153 {
1154 case TCI_SRCFONTSIG:
1155 while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
1156 {
1157 Index++;
1158 }
1159 break;
1160 case TCI_SRCCODEPAGE:
1161 while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciACP)
1162 {
1163 Index++;
1164 }
1165 break;
1166 case TCI_SRCCHARSET:
1167 while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciCharset)
1168 {
1169 Index++;
1170 }
1171 break;
1172 default:
1173 return FALSE;
1174 }
1175
1176 if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == FontTci[Index].ciCharset)
1177 {
1178 return FALSE;
1179 }
1180
1181 RtlCopyMemory(Cs, &FontTci[Index], sizeof(CHARSETINFO));
1182
1183 return TRUE;
1184 }
1185
1186
1187 static BOOL face_has_symbol_charmap(FT_Face ft_face)
1188 {
1189 int i;
1190
1191 for(i = 0; i < ft_face->num_charmaps; i++)
1192 {
1193 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
1194 return TRUE;
1195 }
1196 return FALSE;
1197 }
1198
1199
1200 static void FASTCALL
1201 FillTMEx(TEXTMETRICW *TM, PFONTGDI FontGDI,
1202 TT_OS2 *pOS2, TT_HoriHeader *pHori,
1203 FT_WinFNT_HeaderRec *pFNT, BOOL RealFont)
1204 {
1205 FT_Fixed XScale, YScale;
1206 int Ascent, Descent;
1207 FT_Face Face = FontGDI->SharedFace->Face;
1208
1209 XScale = Face->size->metrics.x_scale;
1210 YScale = Face->size->metrics.y_scale;
1211
1212 if (pFNT)
1213 {
1214 TM->tmHeight = pFNT->pixel_height;
1215 TM->tmAscent = pFNT->ascent;
1216 TM->tmDescent = TM->tmHeight - TM->tmAscent;
1217 TM->tmInternalLeading = pFNT->internal_leading;
1218 TM->tmExternalLeading = pFNT->external_leading;
1219 TM->tmAveCharWidth = pFNT->avg_width;
1220 TM->tmMaxCharWidth = pFNT->max_width;
1221 TM->tmOverhang = 0;
1222 TM->tmDigitizedAspectX = pFNT->horizontal_resolution;
1223 TM->tmDigitizedAspectY = pFNT->vertical_resolution;
1224 TM->tmFirstChar = pFNT->first_char;
1225 TM->tmLastChar = pFNT->last_char;
1226 TM->tmDefaultChar = pFNT->default_char + pFNT->first_char;
1227 TM->tmBreakChar = pFNT->break_char + pFNT->first_char;
1228 TM->tmPitchAndFamily = pFNT->pitch_and_family;
1229 if (RealFont)
1230 {
1231 TM->tmWeight = FontGDI->OriginalWeight;
1232 TM->tmItalic = FontGDI->OriginalItalic;
1233 TM->tmUnderlined = pFNT->underline;
1234 TM->tmStruckOut = pFNT->strike_out;
1235 TM->tmCharSet = pFNT->charset;
1236 }
1237 else
1238 {
1239 TM->tmWeight = FontGDI->RequestWeight;
1240 TM->tmItalic = FontGDI->RequestItalic;
1241 TM->tmUnderlined = FontGDI->RequestUnderline;
1242 TM->tmStruckOut = FontGDI->RequestStrikeOut;
1243 TM->tmCharSet = FontGDI->CharSet;
1244 }
1245 return;
1246 }
1247
1248 if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
1249 {
1250 Ascent = pHori->Ascender;
1251 Descent = -pHori->Descender;
1252 }
1253 else
1254 {
1255 Ascent = pOS2->usWinAscent;
1256 Descent = pOS2->usWinDescent;
1257 }
1258
1259 #if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */
1260 TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
1261 TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
1262 #else /* This (ros) code was previously affected by a FreeType bug, but it works now */
1263 TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* Units above baseline */
1264 TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* Units below baseline */
1265 #endif
1266 TM->tmInternalLeading = (FT_MulFix(Ascent + Descent - Face->units_per_EM, YScale) + 32) >> 6;
1267
1268 TM->tmHeight = TM->tmAscent + TM->tmDescent;
1269
1270 /* MSDN says:
1271 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1272 */
1273 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
1274 - ((Ascent + Descent)
1275 - (pHori->Ascender - pHori->Descender)),
1276 YScale) + 32) >> 6);
1277
1278 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
1279 if (TM->tmAveCharWidth == 0)
1280 {
1281 TM->tmAveCharWidth = 1;
1282 }
1283
1284 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
1285 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
1286
1287 if (RealFont)
1288 {
1289 TM->tmWeight = FontGDI->OriginalWeight;
1290 }
1291 else
1292 {
1293 if (FontGDI->OriginalWeight != FW_DONTCARE &&
1294 FontGDI->OriginalWeight != FW_NORMAL)
1295 {
1296 TM->tmWeight = FontGDI->OriginalWeight;
1297 }
1298 else
1299 {
1300 TM->tmWeight = FontGDI->RequestWeight;
1301 }
1302 }
1303
1304 TM->tmOverhang = 0;
1305 TM->tmDigitizedAspectX = 96;
1306 TM->tmDigitizedAspectY = 96;
1307 if (face_has_symbol_charmap(Face) ||
1308 (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
1309 {
1310 USHORT cpOEM, cpAnsi;
1311
1312 EngGetCurrentCodePage(&cpOEM, &cpAnsi);
1313 TM->tmFirstChar = 0;
1314 switch(cpAnsi)
1315 {
1316 case 1257: /* Baltic */
1317 TM->tmLastChar = 0xf8fd;
1318 break;
1319 default:
1320 TM->tmLastChar = 0xf0ff;
1321 }
1322 TM->tmBreakChar = 0x20;
1323 TM->tmDefaultChar = 0x1f;
1324 }
1325 else
1326 {
1327 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
1328 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
1329
1330 if(pOS2->usFirstCharIndex <= 1)
1331 TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
1332 else if (pOS2->usFirstCharIndex > 0xff)
1333 TM->tmBreakChar = 0x20;
1334 else
1335 TM->tmBreakChar = pOS2->usFirstCharIndex;
1336 TM->tmDefaultChar = TM->tmBreakChar - 1;
1337 }
1338
1339 if (RealFont)
1340 {
1341 TM->tmItalic = FontGDI->OriginalItalic;
1342 TM->tmUnderlined = FALSE;
1343 TM->tmStruckOut = FALSE;
1344 }
1345 else
1346 {
1347 if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
1348 {
1349 TM->tmItalic = 0xFF;
1350 }
1351 else
1352 {
1353 TM->tmItalic = 0;
1354 }
1355 TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
1356 TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
1357 }
1358
1359 if (!FT_IS_FIXED_WIDTH(Face))
1360 {
1361 switch (pOS2->panose[PAN_PROPORTION_INDEX])
1362 {
1363 case PAN_PROP_MONOSPACED:
1364 TM->tmPitchAndFamily = 0;
1365 break;
1366 default:
1367 TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH;
1368 break;
1369 }
1370 }
1371 else
1372 {
1373 TM->tmPitchAndFamily = 0;
1374 }
1375
1376 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
1377 {
1378 case PAN_FAMILY_SCRIPT:
1379 TM->tmPitchAndFamily |= FF_SCRIPT;
1380 break;
1381 case PAN_FAMILY_DECORATIVE:
1382 TM->tmPitchAndFamily |= FF_DECORATIVE;
1383 break;
1384
1385 case PAN_ANY:
1386 case PAN_NO_FIT:
1387 case PAN_FAMILY_TEXT_DISPLAY:
1388 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
1389 /* Which is clearly not what the panose spec says. */
1390 if (TM->tmPitchAndFamily == 0) /* Fixed */
1391 {
1392 TM->tmPitchAndFamily = FF_MODERN;
1393 }
1394 else
1395 {
1396 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
1397 {
1398 case PAN_ANY:
1399 case PAN_NO_FIT:
1400 default:
1401 TM->tmPitchAndFamily |= FF_DONTCARE;
1402 break;
1403
1404 case PAN_SERIF_COVE:
1405 case PAN_SERIF_OBTUSE_COVE:
1406 case PAN_SERIF_SQUARE_COVE:
1407 case PAN_SERIF_OBTUSE_SQUARE_COVE:
1408 case PAN_SERIF_SQUARE:
1409 case PAN_SERIF_THIN:
1410 case PAN_SERIF_BONE:
1411 case PAN_SERIF_EXAGGERATED:
1412 case PAN_SERIF_TRIANGLE:
1413 TM->tmPitchAndFamily |= FF_ROMAN;
1414 break;
1415
1416 case PAN_SERIF_NORMAL_SANS:
1417 case PAN_SERIF_OBTUSE_SANS:
1418 case PAN_SERIF_PERP_SANS:
1419 case PAN_SERIF_FLARED:
1420 case PAN_SERIF_ROUNDED:
1421 TM->tmPitchAndFamily |= FF_SWISS;
1422 break;
1423 }
1424 }
1425 break;
1426 default:
1427 TM->tmPitchAndFamily |= FF_DONTCARE;
1428 }
1429
1430 if (FT_IS_SCALABLE(Face))
1431 {
1432 TM->tmPitchAndFamily |= TMPF_VECTOR;
1433 }
1434 if (FT_IS_SFNT(Face))
1435 {
1436 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
1437 }
1438
1439 TM->tmCharSet = FontGDI->CharSet;
1440 }
1441
1442 static void FASTCALL
1443 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
1444 TT_OS2 *pOS2, TT_HoriHeader *pHori,
1445 FT_WinFNT_HeaderRec *pFNT)
1446 {
1447 FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
1448 }
1449
1450 /*************************************************************
1451 * IntGetOutlineTextMetrics
1452 *
1453 */
1454 INT FASTCALL
1455 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
1456 UINT Size,
1457 OUTLINETEXTMETRICW *Otm)
1458 {
1459 unsigned Needed;
1460 TT_OS2 *pOS2;
1461 TT_HoriHeader *pHori;
1462 TT_Postscript *pPost;
1463 FT_Fixed XScale, YScale;
1464 ANSI_STRING FamilyNameA, StyleNameA;
1465 UNICODE_STRING FamilyNameW, StyleNameW, Regular;
1466 FT_WinFNT_HeaderRec Win;
1467 FT_Error Error;
1468 char *Cp;
1469 NTSTATUS status;
1470 FT_Face Face = FontGDI->SharedFace->Face;
1471
1472 Needed = sizeof(OUTLINETEXTMETRICW);
1473
1474 RtlInitAnsiString(&FamilyNameA, Face->family_name);
1475 status = RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
1476 if (!NT_SUCCESS(status))
1477 {
1478 return 0;
1479 }
1480
1481 RtlInitAnsiString(&StyleNameA, Face->style_name);
1482 status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
1483 if (!NT_SUCCESS(status))
1484 {
1485 RtlFreeUnicodeString(&FamilyNameW);
1486 return 0;
1487 }
1488
1489 /* These names should be read from the TT name table */
1490
1491 /* Length of otmpFamilyName */
1492 Needed += FamilyNameW.Length + sizeof(WCHAR);
1493
1494 RtlInitUnicodeString(&Regular, L"Regular");
1495 /* Length of otmpFaceName */
1496 if (RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
1497 {
1498 Needed += FamilyNameW.Length + sizeof(WCHAR); /* Just the family name */
1499 }
1500 else
1501 {
1502 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
1503 }
1504
1505 /* Length of otmpStyleName */
1506 Needed += StyleNameW.Length + sizeof(WCHAR);
1507
1508 /* Length of otmpFullName */
1509 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
1510
1511 if (Size < Needed)
1512 {
1513 RtlFreeUnicodeString(&FamilyNameW);
1514 RtlFreeUnicodeString(&StyleNameW);
1515 return Needed;
1516 }
1517
1518 XScale = Face->size->metrics.x_scale;
1519 YScale = Face->size->metrics.y_scale;
1520
1521 IntLockFreeType;
1522 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
1523 if (NULL == pOS2)
1524 {
1525 IntUnLockFreeType;
1526 DPRINT1("Can't find OS/2 table - not TT font?\n");
1527 RtlFreeUnicodeString(&StyleNameW);
1528 RtlFreeUnicodeString(&FamilyNameW);
1529 return 0;
1530 }
1531
1532 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
1533 if (NULL == pHori)
1534 {
1535 IntUnLockFreeType;
1536 DPRINT1("Can't find HHEA table - not TT font?\n");
1537 RtlFreeUnicodeString(&StyleNameW);
1538 RtlFreeUnicodeString(&FamilyNameW);
1539 return 0;
1540 }
1541
1542 pPost = FT_Get_Sfnt_Table(Face, ft_sfnt_post); /* We can live with this failing */
1543
1544 Error = FT_Get_WinFNT_Header(Face , &Win);
1545
1546 Otm->otmSize = Needed;
1547
1548 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
1549
1550 Otm->otmFiller = 0;
1551 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1552 Otm->otmfsSelection = pOS2->fsSelection;
1553 Otm->otmfsType = pOS2->fsType;
1554 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1555 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1556 Otm->otmItalicAngle = 0; /* POST table */
1557 Otm->otmEMSquare = Face->units_per_EM;
1558 Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
1559 Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
1560 Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
1561 Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
1562 Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
1563 Otm->otmrcFontBox.left = (FT_MulFix(Face->bbox.xMin, XScale) + 32) >> 6;
1564 Otm->otmrcFontBox.right = (FT_MulFix(Face->bbox.xMax, XScale) + 32) >> 6;
1565 Otm->otmrcFontBox.top = (FT_MulFix(Face->bbox.yMax, YScale) + 32) >> 6;
1566 Otm->otmrcFontBox.bottom = (FT_MulFix(Face->bbox.yMin, YScale) + 32) >> 6;
1567 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
1568 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
1569 Otm->otmMacLineGap = Otm->otmLineGap;
1570 Otm->otmusMinimumPPEM = 0; /* TT Header */
1571 Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
1572 Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
1573 Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
1574 Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
1575 Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
1576 Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
1577 Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
1578 Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
1579 Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
1580 Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
1581 if (!pPost)
1582 {
1583 Otm->otmsUnderscoreSize = 0;
1584 Otm->otmsUnderscorePosition = 0;
1585 }
1586 else
1587 {
1588 Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
1589 Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
1590 }
1591
1592 IntUnLockFreeType;
1593
1594 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1595 Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
1596 Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
1597 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1598 Cp += FamilyNameW.Length + sizeof(WCHAR);
1599 Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
1600 wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
1601 Cp += StyleNameW.Length + sizeof(WCHAR);
1602 Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
1603 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1604 if (!RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
1605 {
1606 wcscat((WCHAR*) Cp, L" ");
1607 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
1608 Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
1609 }
1610 else
1611 {
1612 Cp += FamilyNameW.Length + sizeof(WCHAR);
1613 }
1614 Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
1615 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1616 wcscat((WCHAR*) Cp, L" ");
1617 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
1618
1619 RtlFreeUnicodeString(&StyleNameW);
1620 RtlFreeUnicodeString(&FamilyNameW);
1621
1622 return Needed;
1623 }
1624
1625 static PFONTGDI FASTCALL
1626 FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
1627 {
1628 PLIST_ENTRY Entry;
1629 PFONT_ENTRY CurrentEntry;
1630 ANSI_STRING EntryFaceNameA;
1631 UNICODE_STRING EntryFaceNameW;
1632 FONTGDI *FontGDI;
1633 NTSTATUS status;
1634
1635 Entry = Head->Flink;
1636 while (Entry != Head)
1637 {
1638 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1639
1640 FontGDI = CurrentEntry->Font;
1641 ASSERT(FontGDI);
1642
1643 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
1644 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
1645 if (!NT_SUCCESS(status))
1646 {
1647 break;
1648 }
1649
1650 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
1651 {
1652 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
1653 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
1654 }
1655
1656 if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE))
1657 {
1658 RtlFreeUnicodeString(&EntryFaceNameW);
1659 return FontGDI;
1660 }
1661
1662 RtlFreeUnicodeString(&EntryFaceNameW);
1663 Entry = Entry->Flink;
1664 }
1665
1666 return NULL;
1667 }
1668
1669 static PFONTGDI FASTCALL
1670 FindFaceNameInLists(PUNICODE_STRING FaceName)
1671 {
1672 PPROCESSINFO Win32Process;
1673 PFONTGDI Font;
1674
1675 /* Search the process local list */
1676 Win32Process = PsGetCurrentProcessWin32Process();
1677 IntLockProcessPrivateFonts(Win32Process);
1678 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
1679 IntUnLockProcessPrivateFonts(Win32Process);
1680 if (NULL != Font)
1681 {
1682 return Font;
1683 }
1684
1685 /* Search the global list */
1686 IntLockGlobalFonts;
1687 Font = FindFaceNameInList(FaceName, &FontListHead);
1688 IntUnLockGlobalFonts;
1689
1690 return Font;
1691 }
1692
1693 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
1694 static BYTE
1695 CharSetFromLangID(LANGID LangID)
1696 {
1697 /* FIXME: Add more and fix if wrong */
1698 switch (PRIMARYLANGID(LangID))
1699 {
1700 case LANG_CHINESE:
1701 switch (SUBLANGID(LangID))
1702 {
1703 case SUBLANG_CHINESE_TRADITIONAL:
1704 return CHINESEBIG5_CHARSET;
1705 case SUBLANG_CHINESE_SIMPLIFIED:
1706 default:
1707 break;
1708 }
1709 return GB2312_CHARSET;
1710
1711 case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
1712 case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
1713 return EASTEUROPE_CHARSET;
1714
1715 case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
1716 case LANG_SERBIAN: case LANG_UKRAINIAN:
1717 return RUSSIAN_CHARSET;
1718
1719 case LANG_ARABIC: return ARABIC_CHARSET;
1720 case LANG_GREEK: return GREEK_CHARSET;
1721 case LANG_HEBREW: return HEBREW_CHARSET;
1722 case LANG_JAPANESE: return SHIFTJIS_CHARSET;
1723 case LANG_KOREAN: return JOHAB_CHARSET;
1724 case LANG_TURKISH: return TURKISH_CHARSET;
1725 case LANG_THAI: return THAI_CHARSET;
1726 case LANG_LATVIAN: return BALTIC_CHARSET;
1727 case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
1728
1729 case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
1730 case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
1731 case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
1732 case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
1733 case LANG_SWEDISH: default:
1734 return ANSI_CHARSET;
1735 }
1736 }
1737
1738 static void
1739 SwapEndian(LPVOID pvData, DWORD Size)
1740 {
1741 BYTE b, *pb = pvData;
1742 Size /= 2;
1743 while (Size-- > 0)
1744 {
1745 b = pb[0];
1746 pb[0] = pb[1];
1747 pb[1] = b;
1748 ++pb; ++pb;
1749 }
1750 }
1751
1752 static NTSTATUS
1753 IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face)
1754 {
1755 FT_SfntName Name;
1756 INT i, Count;
1757 WCHAR Buf[LF_FACESIZE];
1758 NTSTATUS Status = STATUS_NOT_FOUND;
1759
1760 RtlInitUnicodeString(pLocalNameW, NULL);
1761
1762 Count = FT_Get_Sfnt_Name_Count(Face);
1763 for (i = 0; i < Count; ++i)
1764 {
1765 FT_Get_Sfnt_Name(Face, i, &Name);
1766 if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
1767 Name.encoding_id != TT_MS_ID_UNICODE_CS)
1768 {
1769 continue; /* not Microsoft Unicode name */
1770 }
1771
1772 if (Name.name_id != TT_NAME_ID_FONT_FAMILY ||
1773 Name.string == NULL || Name.string_len == 0 ||
1774 (Name.string[0] == 0 && Name.string[1] == 0))
1775 {
1776 continue; /* not family name */
1777 }
1778
1779 if (sizeof(Buf) < Name.string_len + sizeof(UNICODE_NULL))
1780 {
1781 continue; /* name too long */
1782 }
1783
1784 /* NOTE: Name.string is not null-terminated */
1785 RtlCopyMemory(Buf, Name.string, Name.string_len);
1786 Buf[Name.string_len / sizeof(WCHAR)] = UNICODE_NULL;
1787
1788 /* Convert UTF-16 big endian to little endian */
1789 SwapEndian(Buf, Name.string_len);
1790 #if 0
1791 DPRINT("IntGetFontLocalizedName: %S (%d)\n", Buf, Name.string_len);
1792 #endif
1793
1794 Status = RtlCreateUnicodeString(pLocalNameW, Buf);
1795 break;
1796 }
1797
1798 return Status;
1799 }
1800
1801 static void FASTCALL
1802 FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
1803 {
1804 ANSI_STRING StyleA;
1805 UNICODE_STRING StyleW;
1806 TT_OS2 *pOS2;
1807 FONTSIGNATURE fs;
1808 CHARSETINFO CharSetInfo;
1809 unsigned i, Size;
1810 OUTLINETEXTMETRICW *Otm;
1811 LOGFONTW *Lf;
1812 TEXTMETRICW *TM;
1813 NEWTEXTMETRICW *Ntm;
1814 DWORD fs0;
1815 NTSTATUS status;
1816 FT_Face Face = FontGDI->SharedFace->Face;
1817
1818 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
1819 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
1820 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
1821 if (!Otm)
1822 {
1823 return;
1824 }
1825 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
1826
1827 Lf = &Info->EnumLogFontEx.elfLogFont;
1828 TM = &Otm->otmTextMetrics;
1829
1830 Lf->lfHeight = TM->tmHeight;
1831 Lf->lfWidth = TM->tmAveCharWidth;
1832 Lf->lfWeight = TM->tmWeight;
1833 Lf->lfItalic = TM->tmItalic;
1834 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
1835 Lf->lfCharSet = TM->tmCharSet;
1836 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
1837 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
1838 Lf->lfQuality = PROOF_QUALITY;
1839
1840 Ntm = &Info->NewTextMetricEx.ntmTm;
1841 Ntm->tmHeight = TM->tmHeight;
1842 Ntm->tmAscent = TM->tmAscent;
1843 Ntm->tmDescent = TM->tmDescent;
1844 Ntm->tmInternalLeading = TM->tmInternalLeading;
1845 Ntm->tmExternalLeading = TM->tmExternalLeading;
1846 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
1847 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
1848 Ntm->tmWeight = TM->tmWeight;
1849 Ntm->tmOverhang = TM->tmOverhang;
1850 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
1851 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
1852 Ntm->tmFirstChar = TM->tmFirstChar;
1853 Ntm->tmLastChar = TM->tmLastChar;
1854 Ntm->tmDefaultChar = TM->tmDefaultChar;
1855 Ntm->tmBreakChar = TM->tmBreakChar;
1856 Ntm->tmItalic = TM->tmItalic;
1857 Ntm->tmUnderlined = TM->tmUnderlined;
1858 Ntm->tmStruckOut = TM->tmStruckOut;
1859 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
1860 Ntm->tmCharSet = TM->tmCharSet;
1861 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
1862
1863 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
1864
1865 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
1866
1867 Ntm->ntmSizeEM = Otm->otmEMSquare;
1868 Ntm->ntmCellHeight = Otm->otmEMSquare;
1869 Ntm->ntmAvgWidth = 0;
1870
1871 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
1872 ? TRUETYPE_FONTTYPE : 0);
1873
1874 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
1875 Info->FontType |= RASTER_FONTTYPE;
1876
1877 ExFreePoolWithTag(Otm, GDITAG_TEXT);
1878
1879 /* try the localized name */
1880 status = STATUS_UNSUCCESSFUL;
1881 if (CharSetFromLangID(gusLanguageID) == FontGDI->CharSet)
1882 {
1883 /* get localized name */
1884 UNICODE_STRING LocalNameW;
1885 status = IntGetFontLocalizedName(&LocalNameW, Face);
1886 if (NT_SUCCESS(status))
1887 {
1888 /* store it */
1889 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
1890 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
1891 LocalNameW.Buffer);
1892 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
1893 sizeof(Info->EnumLogFontEx.elfFullName),
1894 LocalNameW.Buffer);
1895 }
1896 RtlFreeUnicodeString(&LocalNameW);
1897 }
1898
1899 /* if localized name was unavailable */
1900 if (!NT_SUCCESS(status))
1901 {
1902 /* store English name */
1903 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
1904 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
1905 FaceName);
1906 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
1907 sizeof(Info->EnumLogFontEx.elfFullName),
1908 FaceName);
1909 }
1910
1911 RtlInitAnsiString(&StyleA, Face->style_name);
1912 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
1913 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
1914 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
1915 if (!NT_SUCCESS(status))
1916 {
1917 return;
1918 }
1919 if (StyleW.Length)
1920 {
1921 if (wcslen(Info->EnumLogFontEx.elfFullName) +
1922 StyleW.Length / sizeof(WCHAR) + 1 <=
1923 sizeof(Info->EnumLogFontEx.elfFullName))
1924 {
1925 wcscat(Info->EnumLogFontEx.elfFullName, L" ");
1926 wcscat(Info->EnumLogFontEx.elfFullName, StyleW.Buffer);
1927 }
1928 }
1929
1930 Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
1931 Info->EnumLogFontEx.elfScript[0] = L'\0';
1932 IntLockFreeType;
1933 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
1934
1935 if (!pOS2)
1936 {
1937 IntUnLockFreeType;
1938 return;
1939 }
1940
1941 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1942 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1943 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1944 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1945 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1946 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1947
1948 if (0 == pOS2->version)
1949 {
1950 FT_UInt Dummy;
1951
1952 if (FT_Get_First_Char(Face, &Dummy) < 0x100)
1953 fs.fsCsb[0] |= FS_LATIN1;
1954 else
1955 fs.fsCsb[0] |= FS_SYMBOL;
1956 }
1957 IntUnLockFreeType;
1958
1959 if (fs.fsCsb[0] == 0)
1960 {
1961 /* Let's see if we can find any interesting cmaps */
1962 for (i = 0; i < (UINT)Face->num_charmaps; i++)
1963 {
1964 switch (Face->charmaps[i]->encoding)
1965 {
1966 case FT_ENCODING_UNICODE:
1967 case FT_ENCODING_APPLE_ROMAN:
1968 fs.fsCsb[0] |= FS_LATIN1;
1969 break;
1970 case FT_ENCODING_MS_SYMBOL:
1971 fs.fsCsb[0] |= FS_SYMBOL;
1972 break;
1973 default:
1974 break;
1975 }
1976 }
1977 }
1978
1979 for (i = 0; i < MAXTCIINDEX; i++)
1980 {
1981 fs0 = 1L << i;
1982 if (fs.fsCsb[0] & fs0)
1983 {
1984 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
1985 {
1986 CharSetInfo.ciCharset = DEFAULT_CHARSET;
1987 }
1988 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
1989 {
1990 Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
1991 if (ElfScripts[i])
1992 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
1993 else
1994 {
1995 DPRINT1("Unknown elfscript for bit %u\n", i);
1996 }
1997 }
1998 }
1999 }
2000 Info->NewTextMetricEx.ntmFontSig = fs;
2001 }
2002
2003 static int FASTCALL
2004 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
2005 {
2006 DWORD i;
2007 UNICODE_STRING InfoFaceName;
2008
2009 for (i = 0; i < InfoEntries; i++)
2010 {
2011 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
2012 if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE))
2013 {
2014 return i;
2015 }
2016 }
2017
2018 return -1;
2019 }
2020
2021 static BOOLEAN FASTCALL
2022 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
2023 PFONTFAMILYINFO Info, DWORD InfoEntries)
2024 {
2025 UNICODE_STRING LogFontFaceName;
2026
2027 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
2028 if (0 != LogFontFaceName.Length &&
2029 !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE))
2030 {
2031 return FALSE;
2032 }
2033
2034 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
2035 }
2036
2037 static BOOLEAN FASTCALL
2038 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
2039 PFONTFAMILYINFO Info,
2040 DWORD *Count,
2041 DWORD Size,
2042 PLIST_ENTRY Head)
2043 {
2044 PLIST_ENTRY Entry;
2045 PFONT_ENTRY CurrentEntry;
2046 ANSI_STRING EntryFaceNameA;
2047 UNICODE_STRING EntryFaceNameW;
2048 FONTGDI *FontGDI;
2049 NTSTATUS status;
2050
2051 Entry = Head->Flink;
2052 while (Entry != Head)
2053 {
2054 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2055
2056 FontGDI = CurrentEntry->Font;
2057 ASSERT(FontGDI);
2058
2059 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
2060 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2061 if (!NT_SUCCESS(status))
2062 {
2063 return FALSE;
2064 }
2065
2066 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2067 {
2068 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2069 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2070 }
2071
2072 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
2073 {
2074 if (*Count < Size)
2075 {
2076 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
2077 }
2078 (*Count)++;
2079 }
2080 RtlFreeUnicodeString(&EntryFaceNameW);
2081 Entry = Entry->Flink;
2082 }
2083
2084 return TRUE;
2085 }
2086
2087 typedef struct FontFamilyInfoCallbackContext
2088 {
2089 LPLOGFONTW LogFont;
2090 PFONTFAMILYINFO Info;
2091 DWORD Count;
2092 DWORD Size;
2093 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
2094
2095 _Function_class_(RTL_QUERY_REGISTRY_ROUTINE)
2096 static NTSTATUS APIENTRY
2097 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
2098 IN PVOID ValueData, IN ULONG ValueLength,
2099 IN PVOID Context, IN PVOID EntryContext)
2100 {
2101 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
2102 UNICODE_STRING RegistryName, RegistryValue;
2103 int Existing;
2104 PFONTGDI FontGDI;
2105
2106 if (REG_SZ != ValueType)
2107 {
2108 return STATUS_SUCCESS;
2109 }
2110 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
2111 RtlInitUnicodeString(&RegistryName, ValueName);
2112
2113 /* Do we need to include this font family? */
2114 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
2115 min(InfoContext->Count, InfoContext->Size)))
2116 {
2117 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
2118 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
2119 min(InfoContext->Count, InfoContext->Size));
2120 if (0 <= Existing)
2121 {
2122 /* We already have the information about the "real" font. Just copy it */
2123 if (InfoContext->Count < InfoContext->Size)
2124 {
2125 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
2126 RtlStringCbCopyNW(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
2127 sizeof(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName),
2128 RegistryName.Buffer,
2129 RegistryName.Length);
2130 }
2131 InfoContext->Count++;
2132 return STATUS_SUCCESS;
2133 }
2134
2135 /* Try to find information about the "real" font */
2136 FontGDI = FindFaceNameInLists(&RegistryValue);
2137 if (NULL == FontGDI)
2138 {
2139 /* "Real" font not found, discard this registry entry */
2140 return STATUS_SUCCESS;
2141 }
2142
2143 /* Return info about the "real" font but with the name of the alias */
2144 if (InfoContext->Count < InfoContext->Size)
2145 {
2146 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
2147 RegistryName.Buffer, FontGDI);
2148 }
2149 InfoContext->Count++;
2150 return STATUS_SUCCESS;
2151 }
2152
2153 return STATUS_SUCCESS;
2154 }
2155
2156 static BOOLEAN FASTCALL
2157 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
2158 PFONTFAMILYINFO Info,
2159 DWORD *Count,
2160 DWORD Size)
2161 {
2162 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2163 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
2164 NTSTATUS Status;
2165
2166 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
2167 The real work is done in the registry callback function */
2168 Context.LogFont = LogFont;
2169 Context.Info = Info;
2170 Context.Count = *Count;
2171 Context.Size = Size;
2172
2173 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
2174 QueryTable[0].Flags = 0;
2175 QueryTable[0].Name = NULL;
2176 QueryTable[0].EntryContext = NULL;
2177 QueryTable[0].DefaultType = REG_NONE;
2178 QueryTable[0].DefaultData = NULL;
2179 QueryTable[0].DefaultLength = 0;
2180
2181 QueryTable[1].QueryRoutine = NULL;
2182 QueryTable[1].Name = NULL;
2183
2184 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2185 L"FontSubstitutes",
2186 QueryTable,
2187 &Context,
2188 NULL);
2189 if (NT_SUCCESS(Status))
2190 {
2191 *Count = Context.Count;
2192 }
2193
2194 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
2195 }
2196
2197 BOOL
2198 FASTCALL
2199 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
2200 {
2201 if ( lprs )
2202 {
2203 lprs->nSize = sizeof(RASTERIZER_STATUS);
2204 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
2205 lprs->nLanguageID = gusLanguageID;
2206 return TRUE;
2207 }
2208 EngSetLastError(ERROR_INVALID_PARAMETER);
2209 return FALSE;
2210 }
2211
2212 static
2213 BOOL
2214 SameScaleMatrix(
2215 PMATRIX pmx1,
2216 PMATRIX pmx2)
2217 {
2218 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
2219 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
2220 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
2221 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
2222 }
2223
2224 FT_BitmapGlyph APIENTRY
2225 ftGdiGlyphCacheGet(
2226 FT_Face Face,
2227 INT GlyphIndex,
2228 INT Height,
2229 PMATRIX pmx)
2230 {
2231 PLIST_ENTRY CurrentEntry;
2232 PFONT_CACHE_ENTRY FontEntry;
2233
2234 CurrentEntry = FontCacheListHead.Flink;
2235 while (CurrentEntry != &FontCacheListHead)
2236 {
2237 FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
2238 if ((FontEntry->Face == Face) &&
2239 (FontEntry->GlyphIndex == GlyphIndex) &&
2240 (FontEntry->Height == Height) &&
2241 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2242 break;
2243 CurrentEntry = CurrentEntry->Flink;
2244 }
2245
2246 if (CurrentEntry == &FontCacheListHead)
2247 {
2248 return NULL;
2249 }
2250
2251 RemoveEntryList(CurrentEntry);
2252 InsertHeadList(&FontCacheListHead, CurrentEntry);
2253 return FontEntry->BitmapGlyph;
2254 }
2255
2256 /* no cache */
2257 FT_BitmapGlyph APIENTRY
2258 ftGdiGlyphSet(
2259 FT_Face Face,
2260 FT_GlyphSlot GlyphSlot,
2261 FT_Render_Mode RenderMode)
2262 {
2263 FT_Glyph Glyph;
2264 INT error;
2265 FT_Bitmap AlignedBitmap;
2266 FT_BitmapGlyph BitmapGlyph;
2267
2268 error = FT_Get_Glyph(GlyphSlot, &Glyph);
2269 if (error)
2270 {
2271 DPRINT1("Failure getting glyph.\n");
2272 return NULL;
2273 }
2274
2275 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2276 if (error)
2277 {
2278 FT_Done_Glyph(Glyph);
2279 DPRINT1("Failure rendering glyph.\n");
2280 return NULL;
2281 }
2282
2283 BitmapGlyph = (FT_BitmapGlyph)Glyph;
2284 FT_Bitmap_New(&AlignedBitmap);
2285 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2286 {
2287 DPRINT1("Conversion failed\n");
2288 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2289 return NULL;
2290 }
2291
2292 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2293 BitmapGlyph->bitmap = AlignedBitmap;
2294
2295 return BitmapGlyph;
2296 }
2297
2298 FT_BitmapGlyph APIENTRY
2299 ftGdiGlyphCacheSet(
2300 FT_Face Face,
2301 INT GlyphIndex,
2302 INT Height,
2303 PMATRIX pmx,
2304 FT_GlyphSlot GlyphSlot,
2305 FT_Render_Mode RenderMode)
2306 {
2307 FT_Glyph GlyphCopy;
2308 INT error;
2309 PFONT_CACHE_ENTRY NewEntry;
2310 FT_Bitmap AlignedBitmap;
2311 FT_BitmapGlyph BitmapGlyph;
2312
2313 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2314 if (error)
2315 {
2316 DPRINT1("Failure caching glyph.\n");
2317 return NULL;
2318 };
2319
2320 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2321 if (error)
2322 {
2323 FT_Done_Glyph(GlyphCopy);
2324 DPRINT1("Failure rendering glyph.\n");
2325 return NULL;
2326 };
2327
2328 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
2329 if (!NewEntry)
2330 {
2331 DPRINT1("Alloc failure caching glyph.\n");
2332 FT_Done_Glyph(GlyphCopy);
2333 return NULL;
2334 }
2335
2336 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2337 FT_Bitmap_New(&AlignedBitmap);
2338 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2339 {
2340 DPRINT1("Conversion failed\n");
2341 ExFreePoolWithTag(NewEntry, TAG_FONT);
2342 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2343 return NULL;
2344 }
2345
2346 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2347 BitmapGlyph->bitmap = AlignedBitmap;
2348
2349 NewEntry->GlyphIndex = GlyphIndex;
2350 NewEntry->Face = Face;
2351 NewEntry->BitmapGlyph = BitmapGlyph;
2352 NewEntry->Height = Height;
2353 NewEntry->mxWorldToDevice = *pmx;
2354
2355 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
2356 if (FontCacheNumEntries++ > MAX_FONT_CACHE)
2357 {
2358 NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
2359 FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph);
2360 RemoveTailList(&FontCacheListHead);
2361 ExFreePoolWithTag(NewEntry, TAG_FONT);
2362 FontCacheNumEntries--;
2363 }
2364
2365 return BitmapGlyph;
2366 }
2367
2368
2369 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2370 {
2371 pt->x.value = vec->x >> 6;
2372 pt->x.fract = (vec->x & 0x3f) << 10;
2373 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2374 pt->y.value = vec->y >> 6;
2375 pt->y.fract = (vec->y & 0x3f) << 10;
2376 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2377 }
2378
2379 /*
2380 This function builds an FT_Fixed from a float. It puts the integer part
2381 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2382 It fails if the integer part of the float number is greater than SHORT_MAX.
2383 */
2384 static __inline FT_Fixed FT_FixedFromFloat(float f)
2385 {
2386 short value = f;
2387 unsigned short fract = (f - value) * 0xFFFF;
2388 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2389 }
2390
2391 /*
2392 This function builds an FT_Fixed from a FIXED. It simply put f.value
2393 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2394 */
2395 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2396 {
2397 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2398 }
2399
2400 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2401 {
2402 TTPOLYGONHEADER *pph;
2403 TTPOLYCURVE *ppc;
2404 int needed = 0, point = 0, contour, first_pt;
2405 unsigned int pph_start, cpfx;
2406 DWORD type;
2407
2408 for (contour = 0; contour < outline->n_contours; contour++)
2409 {
2410 /* Ignore contours containing one point */
2411 if (point == outline->contours[contour])
2412 {
2413 point++;
2414 continue;
2415 }
2416
2417 pph_start = needed;
2418 pph = (TTPOLYGONHEADER *)(buf + needed);
2419 first_pt = point;
2420 if (buf)
2421 {
2422 pph->dwType = TT_POLYGON_TYPE;
2423 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2424 }
2425 needed += sizeof(*pph);
2426 point++;
2427 while (point <= outline->contours[contour])
2428 {
2429 ppc = (TTPOLYCURVE *)(buf + needed);
2430 type = outline->tags[point] & FT_Curve_Tag_On ?
2431 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2432 cpfx = 0;
2433 do
2434 {
2435 if (buf)
2436 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2437 cpfx++;
2438 point++;
2439 } while (point <= outline->contours[contour] &&
2440 (outline->tags[point] & FT_Curve_Tag_On) ==
2441 (outline->tags[point-1] & FT_Curve_Tag_On));
2442 /* At the end of a contour Windows adds the start point, but
2443 only for Beziers */
2444 if (point > outline->contours[contour] &&
2445 !(outline->tags[point-1] & FT_Curve_Tag_On))
2446 {
2447 if (buf)
2448 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2449 cpfx++;
2450 }
2451 else if (point <= outline->contours[contour] &&
2452 outline->tags[point] & FT_Curve_Tag_On)
2453 {
2454 /* add closing pt for bezier */
2455 if (buf)
2456 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2457 cpfx++;
2458 point++;
2459 }
2460 if (buf)
2461 {
2462 ppc->wType = type;
2463 ppc->cpfx = cpfx;
2464 }
2465 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2466 }
2467 if (buf)
2468 pph->cb = needed - pph_start;
2469 }
2470 return needed;
2471 }
2472
2473 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2474 {
2475 /* Convert the quadratic Beziers to cubic Beziers.
2476 The parametric eqn for a cubic Bezier is, from PLRM:
2477 r(t) = at^3 + bt^2 + ct + r0
2478 with the control points:
2479 r1 = r0 + c/3
2480 r2 = r1 + (c + b)/3
2481 r3 = r0 + c + b + a
2482
2483 A quadratic Bezier has the form:
2484 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2485
2486 So equating powers of t leads to:
2487 r1 = 2/3 p1 + 1/3 p0
2488 r2 = 2/3 p1 + 1/3 p2
2489 and of course r0 = p0, r3 = p2
2490 */
2491 int contour, point = 0, first_pt;
2492 TTPOLYGONHEADER *pph;
2493 TTPOLYCURVE *ppc;
2494 DWORD pph_start, cpfx, type;
2495 FT_Vector cubic_control[4];
2496 unsigned int needed = 0;
2497
2498 for (contour = 0; contour < outline->n_contours; contour++)
2499 {
2500 pph_start = needed;
2501 pph = (TTPOLYGONHEADER *)(buf + needed);
2502 first_pt = point;
2503 if (buf)
2504 {
2505 pph->dwType = TT_POLYGON_TYPE;
2506 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2507 }
2508 needed += sizeof(*pph);
2509 point++;
2510 while (point <= outline->contours[contour])
2511 {
2512 ppc = (TTPOLYCURVE *)(buf + needed);
2513 type = outline->tags[point] & FT_Curve_Tag_On ?
2514 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2515 cpfx = 0;
2516 do
2517 {
2518 if (type == TT_PRIM_LINE)
2519 {
2520 if (buf)
2521 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2522 cpfx++;
2523 point++;
2524 }
2525 else
2526 {
2527 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2528 so cpfx = 3n */
2529
2530 /* FIXME: Possible optimization in endpoint calculation
2531 if there are two consecutive curves */
2532 cubic_control[0] = outline->points[point-1];
2533 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2534 {
2535 cubic_control[0].x += outline->points[point].x + 1;
2536 cubic_control[0].y += outline->points[point].y + 1;
2537 cubic_control[0].x >>= 1;
2538 cubic_control[0].y >>= 1;
2539 }
2540 if (point+1 > outline->contours[contour])
2541 cubic_control[3] = outline->points[first_pt];
2542 else
2543 {
2544 cubic_control[3] = outline->points[point+1];
2545 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2546 {
2547 cubic_control[3].x += outline->points[point].x + 1;
2548 cubic_control[3].y += outline->points[point].y + 1;
2549 cubic_control[3].x >>= 1;
2550 cubic_control[3].y >>= 1;
2551 }
2552 }
2553 /* r1 = 1/3 p0 + 2/3 p1
2554 r2 = 1/3 p2 + 2/3 p1 */
2555 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2556 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2557 cubic_control[2] = cubic_control[1];
2558 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2559 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2560 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2561 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2562 if (buf)
2563 {
2564 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2565 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2566 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2567 }
2568 cpfx += 3;
2569 point++;
2570 }
2571 } while (point <= outline->contours[contour] &&
2572 (outline->tags[point] & FT_Curve_Tag_On) ==
2573 (outline->tags[point-1] & FT_Curve_Tag_On));
2574 /* At the end of a contour Windows adds the start point,
2575 but only for Beziers and we've already done that.
2576 */
2577 if (point <= outline->contours[contour] &&
2578 outline->tags[point] & FT_Curve_Tag_On)
2579 {
2580 /* This is the closing pt of a bezier, but we've already
2581 added it, so just inc point and carry on */
2582 point++;
2583 }
2584 if (buf)
2585 {
2586 ppc->wType = type;
2587 ppc->cpfx = cpfx;
2588 }
2589 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2590 }
2591 if (buf)
2592 pph->cb = needed - pph_start;
2593 }
2594 return needed;
2595 }
2596
2597 static INT
2598 IntRequestFontSize(PDC dc, FT_Face face, LONG Width, LONG Height)
2599 {
2600 FT_Size_RequestRec req;
2601
2602 if (Width < 0)
2603 Width = -Width;
2604
2605 if (Height < 0)
2606 {
2607 Height = -Height;
2608 }
2609 if (Height == 0)
2610 {
2611 Height = dc->ppdev->devinfo.lfDefaultFont.lfHeight;
2612 }
2613 if (Height == 0)
2614 {
2615 Height = Width;
2616 }
2617
2618 if (Height < 1)
2619 Height = 1;
2620
2621 if (Width > 0xFFFFU)
2622 Width = 0xFFFFU;
2623 if (Height > 0xFFFFU)
2624 Height = 0xFFFFU;
2625
2626 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
2627 req.width = (FT_Long)(Width << 6);
2628 req.height = (FT_Long)(Height << 6);
2629 req.horiResolution = 0;
2630 req.vertResolution = 0;
2631 return FT_Request_Size(face, &req);
2632 }
2633
2634 BOOL
2635 FASTCALL
2636 TextIntUpdateSize(PDC dc,
2637 PTEXTOBJ TextObj,
2638 PFONTGDI FontGDI,
2639 BOOL bDoLock)
2640 {
2641 FT_Face face;
2642 INT error, n;
2643 FT_CharMap charmap, found;
2644 LOGFONTW *plf;
2645
2646 if (bDoLock)
2647 IntLockFreeType;
2648
2649 face = FontGDI->SharedFace->Face;
2650 if (face->charmap == NULL)
2651 {
2652 DPRINT("WARNING: No charmap selected!\n");
2653 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2654
2655 found = NULL;
2656 for (n = 0; n < face->num_charmaps; n++)
2657 {
2658 charmap = face->charmaps[n];
2659 DPRINT("Found charmap encoding: %i\n", charmap->encoding);
2660 if (charmap->encoding != 0)
2661 {
2662 found = charmap;
2663 break;
2664 }
2665 }
2666 if (!found)
2667 {
2668 DPRINT1("WARNING: Could not find desired charmap!\n");
2669 }
2670 else
2671 {
2672 error = FT_Set_Charmap(face, found);
2673 if (error)
2674 {
2675 DPRINT1("WARNING: Could not set the charmap!\n");
2676 }
2677 }
2678 }
2679
2680 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
2681
2682 error = IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
2683
2684 if (bDoLock)
2685 IntUnLockFreeType;
2686
2687 if (error)
2688 {
2689 DPRINT1("Error in setting pixel sizes: %d\n", error);
2690 return FALSE;
2691 }
2692
2693 return TRUE;
2694 }
2695
2696
2697 /*
2698 * Based on WineEngGetGlyphOutline
2699 *
2700 */
2701 ULONG
2702 FASTCALL
2703 ftGdiGetGlyphOutline(
2704 PDC dc,
2705 WCHAR wch,
2706 UINT iFormat,
2707 LPGLYPHMETRICS pgm,
2708 ULONG cjBuf,
2709 PVOID pvBuf,
2710 LPMAT2 pmat2,
2711 BOOL bIgnoreRotation)
2712 {
2713 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2714 PDC_ATTR pdcattr;
2715 PTEXTOBJ TextObj;
2716 PFONTGDI FontGDI;
2717 HFONT hFont = 0;
2718 GLYPHMETRICS gm;
2719 ULONG Size;
2720 FT_Face ft_face;
2721 FT_UInt glyph_index;
2722 DWORD width, height, pitch, needed = 0;
2723 FT_Bitmap ft_bitmap;
2724 FT_Error error;
2725 INT left, right, top = 0, bottom = 0;
2726 FT_Angle angle = 0;
2727 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2728 FLOAT eM11, widthRatio = 1.0;
2729 FT_Matrix transMat = identityMat;
2730 BOOL needsTransform = FALSE;
2731 INT orientation;
2732 LONG aveWidth;
2733 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
2734 OUTLINETEXTMETRICW *potm;
2735 XFORM xForm;
2736 LOGFONTW *plf;
2737
2738 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
2739 cjBuf, pvBuf, pmat2);
2740
2741 pdcattr = dc->pdcattr;
2742
2743 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
2744 eM11 = xForm.eM11;
2745
2746 hFont = pdcattr->hlfntNew;
2747 TextObj = RealizeFontInit(hFont);
2748
2749 if (!TextObj)
2750 {
2751 EngSetLastError(ERROR_INVALID_HANDLE);
2752 return GDI_ERROR;
2753 }
2754 FontGDI = ObjToGDI(TextObj->Font, FONT);
2755 ft_face = FontGDI->SharedFace->Face;
2756
2757 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
2758 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
2759 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
2760
2761 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2762 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2763 if (!potm)
2764 {
2765 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2766 TEXTOBJ_UnlockText(TextObj);
2767 return GDI_ERROR;
2768 }
2769 IntGetOutlineTextMetrics(FontGDI, Size, potm);
2770
2771 IntLockFreeType;
2772 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
2773 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
2774
2775 TEXTOBJ_UnlockText(TextObj);
2776
2777 if (iFormat & GGO_GLYPH_INDEX)
2778 {
2779 glyph_index = wch;
2780 iFormat &= ~GGO_GLYPH_INDEX;
2781 }
2782 else glyph_index = FT_Get_Char_Index(ft_face, wch);
2783
2784 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
2785 load_flags |= FT_LOAD_NO_BITMAP;
2786
2787 if (iFormat & GGO_UNHINTED)
2788 {
2789 load_flags |= FT_LOAD_NO_HINTING;
2790 iFormat &= ~GGO_UNHINTED;
2791 }
2792
2793 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
2794 if (error)
2795 {
2796 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
2797 IntUnLockFreeType;
2798 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
2799 return GDI_ERROR;
2800 }
2801 IntUnLockFreeType;
2802
2803 if (aveWidth && potm)
2804 {
2805 widthRatio = (FLOAT)aveWidth * eM11 /
2806 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
2807 }
2808
2809 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2810 right = (INT)((ft_face->glyph->metrics.horiBearingX +
2811 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2812
2813 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2814 lsb = left >> 6;
2815 bbx = (right - left) >> 6;
2816
2817 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
2818
2819 IntLockFreeType;
2820
2821 /* Scaling transform */
2822 /*if (aveWidth)*/
2823 {
2824
2825 FT_Matrix ftmatrix;
2826 FLOATOBJ efTemp;
2827
2828 PMATRIX pmx = DC_pmxWorldToDevice(dc);
2829
2830 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
2831 efTemp = pmx->efM11;
2832 FLOATOBJ_MulLong(&efTemp, 0x00010000);
2833 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
2834
2835 efTemp = pmx->efM12;
2836 FLOATOBJ_MulLong(&efTemp, 0x00010000);
2837 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
2838
2839 efTemp = pmx->efM21;
2840 FLOATOBJ_MulLong(&efTemp, 0x00010000);
2841 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
2842
2843 efTemp = pmx->efM22;
2844 FLOATOBJ_MulLong(&efTemp, 0x00010000);
2845 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
2846
2847 FT_Matrix_Multiply(&ftmatrix, &transMat);
2848 needsTransform = TRUE;
2849 }
2850
2851 /* Rotation transform */
2852 if (orientation)
2853 {
2854 FT_Matrix rotationMat;
2855 FT_Vector vecAngle;
2856 DPRINT("Rotation Trans!\n");
2857 angle = FT_FixedFromFloat((float)orientation / 10.0);
2858 FT_Vector_Unit(&vecAngle, angle);
2859 rotationMat.xx = vecAngle.x;
2860 rotationMat.xy = -vecAngle.y;
2861 rotationMat.yx = -rotationMat.xy;
2862 rotationMat.yy = rotationMat.xx;
2863 FT_Matrix_Multiply(&rotationMat, &transMat);
2864 needsTransform = TRUE;
2865 }
2866
2867 /* Extra transformation specified by caller */
2868 if (pmat2)
2869 {
2870 FT_Matrix extraMat;
2871 DPRINT("MAT2 Matrix Trans!\n");
2872 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
2873 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
2874 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
2875 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
2876 FT_Matrix_Multiply(&extraMat, &transMat);
2877 needsTransform = TRUE;
2878 }
2879
2880 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
2881
2882 if (!needsTransform)
2883 {
2884 DPRINT("No Need to be Transformed!\n");
2885 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2886 bottom = (ft_face->glyph->metrics.horiBearingY -
2887 ft_face->glyph->metrics.height) & -64;
2888 gm.gmCellIncX = adv;
2889 gm.gmCellIncY = 0;
2890 }
2891 else
2892 {
2893 INT xc, yc;
2894 FT_Vector vec;
2895 for (xc = 0; xc < 2; xc++)
2896 {
2897 for (yc = 0; yc < 2; yc++)
2898 {
2899 vec.x = (ft_face->glyph->metrics.horiBearingX +
2900 xc * ft_face->glyph->metrics.width);
2901 vec.y = ft_face->glyph->metrics.horiBearingY -
2902 yc * ft_face->glyph->metrics.height;
2903 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
2904 FT_Vector_Transform(&vec, &transMat);
2905 if (xc == 0 && yc == 0)
2906 {
2907 left = right = vec.x;
2908 top = bottom = vec.y;
2909 }
2910 else
2911 {
2912 if (vec.x < left) left = vec.x;
2913 else if (vec.x > right) right = vec.x;
2914 if (vec.y < bottom) bottom = vec.y;
2915 else if (vec.y > top) top = vec.y;
2916 }
2917 }
2918 }
2919 left = left & -64;
2920 right = (right + 63) & -64;
2921 bottom = bottom & -64;
2922 top = (top + 63) & -64;
2923
2924 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2925 vec.x = ft_face->glyph->metrics.horiAdvance;
2926 vec.y = 0;
2927 FT_Vector_Transform(&vec, &transMat);
2928 gm.gmCellIncX = (vec.x+63) >> 6;
2929 gm.gmCellIncY = -((vec.y+63) >> 6);
2930 }
2931 gm.gmBlackBoxX = (right - left) >> 6;
2932 gm.gmBlackBoxY = (top - bottom) >> 6;
2933 gm.gmptGlyphOrigin.x = left >> 6;
2934 gm.gmptGlyphOrigin.y = top >> 6;
2935
2936 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
2937 gm.gmCellIncX, gm.gmCellIncY,
2938 gm.gmBlackBoxX, gm.gmBlackBoxY,
2939 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
2940
2941 IntUnLockFreeType;
2942
2943
2944 if (iFormat == GGO_METRICS)
2945 {
2946 DPRINT("GGO_METRICS Exit!\n");
2947 *pgm = gm;
2948 return 1; /* FIXME */
2949 }
2950
2951 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
2952 {
2953 DPRINT1("Loaded a bitmap\n");
2954 return GDI_ERROR;
2955 }
2956
2957 switch (iFormat)
2958 {
2959 case GGO_BITMAP:
2960 width = gm.gmBlackBoxX;
2961 height = gm.gmBlackBoxY;
2962 pitch = ((width + 31) >> 5) << 2;
2963 needed = pitch * height;
2964
2965 if (!pvBuf || !cjBuf) break;
2966 if (!needed) return GDI_ERROR; /* empty glyph */
2967 if (needed > cjBuf)
2968 return GDI_ERROR;
2969
2970 switch (ft_face->glyph->format)
2971 {
2972 case ft_glyph_format_bitmap:
2973 {
2974 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
2975 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
2976 INT h = min( height, ft_face->glyph->bitmap.rows );
2977 while (h--)
2978 {
2979 RtlCopyMemory(dst, src, w);
2980 src += ft_face->glyph->bitmap.pitch;
2981 dst += pitch;
2982 }
2983 break;
2984 }
2985
2986 case ft_glyph_format_outline:
2987 ft_bitmap.width = width;
2988 ft_bitmap.rows = height;
2989 ft_bitmap.pitch = pitch;
2990 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
2991 ft_bitmap.buffer = pvBuf;
2992
2993 IntLockFreeType;
2994 if (needsTransform)
2995 {
2996 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2997 }
2998 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2999 /* Note: FreeType will only set 'black' bits for us. */
3000 RtlZeroMemory(pvBuf, needed);
3001 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3002 IntUnLockFreeType;
3003 break;
3004
3005 default:
3006 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3007 return GDI_ERROR;
3008 }
3009 break;
3010
3011 case GGO_GRAY2_BITMAP:
3012 case GGO_GRAY4_BITMAP:
3013 case GGO_GRAY8_BITMAP:
3014 {
3015 unsigned int mult, row, col;
3016 BYTE *start, *ptr;
3017
3018 width = gm.gmBlackBoxX;
3019 height = gm.gmBlackBoxY;
3020 pitch = (width + 3) / 4 * 4;
3021 needed = pitch * height;
3022
3023 if (!pvBuf || !cjBuf) break;
3024 if (!needed) return GDI_ERROR; /* empty glyph */
3025 if (needed > cjBuf)
3026 return GDI_ERROR;
3027
3028 switch (ft_face->glyph->format)
3029 {
3030 case ft_glyph_format_bitmap:
3031 {
3032 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3033 INT h = min( height, ft_face->glyph->bitmap.rows );
3034 INT x;
3035 while (h--)
3036 {
3037 for (x = 0; (UINT)x < pitch; x++)
3038 {
3039 if (x < ft_face->glyph->bitmap.width)
3040 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3041 else
3042 dst[x] = 0;
3043 }
3044 src += ft_face->glyph->bitmap.pitch;
3045 dst += pitch;
3046 }
3047 break;
3048 }
3049 case ft_glyph_format_outline:
3050 {
3051 ft_bitmap.width = width;
3052 ft_bitmap.rows = height;
3053 ft_bitmap.pitch = pitch;
3054 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3055 ft_bitmap.buffer = pvBuf;
3056
3057 IntLockFreeType;
3058 if (needsTransform)
3059 {
3060 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3061 }
3062 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3063 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
3064 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3065 IntUnLockFreeType;
3066
3067 if (iFormat == GGO_GRAY2_BITMAP)
3068 mult = 4;
3069 else if (iFormat == GGO_GRAY4_BITMAP)
3070 mult = 16;
3071 else if (iFormat == GGO_GRAY8_BITMAP)
3072 mult = 64;
3073 else
3074 {
3075 return GDI_ERROR;
3076 }
3077
3078 start = pvBuf;
3079 for (row = 0; row < height; row++)
3080 {
3081 ptr = start;
3082 for (col = 0; col < width; col++, ptr++)
3083 {
3084 *ptr = (((int)*ptr) * mult + 128) / 256;
3085 }
3086 start += pitch;
3087 }
3088
3089 break;
3090 }
3091 default:
3092 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3093 return GDI_ERROR;
3094 }
3095 }
3096
3097 case GGO_NATIVE:
3098 {
3099 FT_Outline *outline = &ft_face->glyph->outline;
3100
3101 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
3102
3103 IntLockFreeType;
3104 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
3105
3106 needed = get_native_glyph_outline(outline, cjBuf, NULL);
3107
3108 if (!pvBuf || !cjBuf)
3109 {
3110 IntUnLockFreeType;
3111 break;
3112 }
3113 if (needed > cjBuf)
3114 {
3115 IntUnLockFreeType;
3116 return GDI_ERROR;
3117 }
3118 get_native_glyph_outline(outline, cjBuf, pvBuf);
3119 IntUnLockFreeType;
3120 break;
3121 }
3122 case GGO_BEZIER:
3123 {
3124 FT_Outline *outline = &ft_face->glyph->outline;
3125 if (cjBuf == 0) pvBuf = NULL;
3126
3127 if (needsTransform && pvBuf)
3128 {
3129 IntLockFreeType;
3130 FT_Outline_Transform(outline, &transMat);
3131 IntUnLockFreeType;
3132 }
3133 needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
3134
3135 if (!pvBuf || !cjBuf)
3136 break;
3137 if (needed > cjBuf)
3138 return GDI_ERROR;
3139
3140 get_bezier_glyph_outline(outline, cjBuf, pvBuf);
3141 break;
3142 }
3143
3144 default:
3145 DPRINT1("Unsupported format %u\n", iFormat);
3146 return GDI_ERROR;
3147 }
3148
3149 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
3150 *pgm = gm;
3151 return needed;
3152 }
3153
3154 BOOL
3155 FASTCALL
3156 TextIntGetTextExtentPoint(PDC dc,
3157 PTEXTOBJ TextObj,
3158 LPCWSTR String,
3159 INT Count,
3160 ULONG MaxExtent,
3161 LPINT Fit,
3162 LPINT Dx,
3163 LPSIZE Size,
3164 FLONG fl)
3165 {
3166 PFONTGDI FontGDI;
3167 FT_Face face;
3168 FT_GlyphSlot glyph;
3169 FT_BitmapGlyph realglyph;
3170 INT error, glyph_index, i, previous;
3171 ULONGLONG TotalWidth = 0;
3172 BOOL use_kerning;
3173 FT_Render_Mode RenderMode;
3174 BOOLEAN Render;
3175 PMATRIX pmxWorldToDevice;
3176 LOGFONTW *plf;
3177 BOOL EmuBold, EmuItalic;
3178
3179 FontGDI = ObjToGDI(TextObj->Font, FONT);
3180
3181 face = FontGDI->SharedFace->Face;
3182 if (NULL != Fit)
3183 {
3184 *Fit = 0;
3185 }
3186
3187 IntLockFreeType;
3188
3189 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3190
3191 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3192 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
3193 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
3194
3195 Render = IntIsFontRenderingEnabled();
3196 if (Render)
3197 RenderMode = IntGetFontRenderMode(plf);
3198 else
3199 RenderMode = FT_RENDER_MODE_MONO;
3200
3201
3202 /* Get the DC's world-to-device transformation matrix */
3203 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3204 FtSetCoordinateTransform(face, pmxWorldToDevice);
3205
3206 use_kerning = FT_HAS_KERNING(face);
3207 previous = 0;
3208
3209 for (i = 0; i < Count; i++)
3210 {
3211 if (fl & GTEF_INDICES)
3212 glyph_index = *String;
3213 else
3214 glyph_index = FT_Get_Char_Index(face, *String);
3215
3216 if (EmuBold || EmuItalic)
3217 realglyph = NULL;
3218 else
3219 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3220 plf->lfHeight, pmxWorldToDevice);
3221
3222 if (EmuBold || EmuItalic || !realglyph)
3223 {
3224 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3225 if (error)
3226 {
3227 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
3228 break;
3229 }
3230
3231 glyph = face->glyph;
3232 if (EmuBold || EmuItalic)
3233 {
3234 if (EmuBold)
3235 FT_GlyphSlot_Embolden(glyph);
3236 if (EmuItalic)
3237 FT_GlyphSlot_Oblique(glyph);
3238 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
3239 }
3240 else
3241 {
3242 realglyph = ftGdiGlyphCacheSet(face,
3243 glyph_index,
3244 plf->lfHeight,
3245 pmxWorldToDevice,
3246 glyph,
3247 RenderMode);
3248 }
3249
3250 if (!realglyph)
3251 {
3252 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3253 break;
3254 }
3255 }
3256
3257 /* Retrieve kerning distance */
3258 if (use_kerning && previous && glyph_index)
3259 {
3260 FT_Vector delta;
3261 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3262 TotalWidth += delta.x;
3263 }
3264
3265 TotalWidth += realglyph->root.advance.x >> 10;
3266
3267 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
3268 {
3269 *Fit = i + 1;
3270 }
3271 if (NULL != Dx)
3272 {
3273 Dx[i] = (TotalWidth + 32) >> 6;
3274 }
3275
3276 if (EmuBold || EmuItalic)
3277 {
3278 FT_Done_Glyph((FT_Glyph)realglyph);
3279 realglyph = NULL;
3280 }
3281
3282 previous = glyph_index;
3283 String++;
3284 }
3285 IntUnLockFreeType;
3286
3287 Size->cx = (TotalWidth + 32) >> 6;
3288 Size->cy = (plf->lfHeight == 0 ?
3289 dc->ppdev->devinfo.lfDefaultFont.lfHeight :
3290 abs(plf->lfHeight));
3291 Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
3292
3293 return TRUE;
3294 }
3295
3296
3297 INT
3298 FASTCALL
3299 ftGdiGetTextCharsetInfo(
3300 PDC Dc,
3301 LPFONTSIGNATURE lpSig,
3302 DWORD dwFlags)
3303 {
3304 PDC_ATTR pdcattr;
3305 UINT Ret = DEFAULT_CHARSET;
3306 INT i;
3307 HFONT hFont;
3308 PTEXTOBJ TextObj;
3309 PFONTGDI FontGdi;
3310 FONTSIGNATURE fs;
3311 TT_OS2 *pOS2;
3312 FT_Face Face;
3313 CHARSETINFO csi;
3314 DWORD cp, fs0;
3315 USHORT usACP, usOEM;
3316
3317 pdcattr = Dc->pdcattr;
3318 hFont = pdcattr->hlfntNew;
3319 TextObj = RealizeFontInit(hFont);
3320
3321 if (!TextObj)
3322 {
3323 EngSetLastError(ERROR_INVALID_HANDLE);
3324 return Ret;
3325 }
3326 FontGdi = ObjToGDI(TextObj->Font, FONT);
3327 Face = FontGdi->SharedFace->Face;
3328 TEXTOBJ_UnlockText(TextObj);
3329
3330 IntLockFreeType;
3331 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3332 IntUnLockFreeType;
3333 memset(&fs, 0, sizeof(FONTSIGNATURE));
3334 if (NULL != pOS2)
3335 {
3336 fs.fsCsb[0] = pOS2->ulCodePageRange1;
3337 fs.fsCsb[1] = pOS2->ulCodePageRange2;
3338 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3339 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3340 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3341 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3342 if (pOS2->version == 0)
3343 {
3344 FT_UInt dummy;
3345
3346 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
3347 fs.fsCsb[0] |= FS_LATIN1;
3348 else
3349 fs.fsCsb[0] |= FS_SYMBOL;
3350 }
3351 }
3352 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
3353 if (fs.fsCsb[0] == 0)
3354 { /* Let's see if we can find any interesting cmaps */
3355 for (i = 0; i < Face->num_charmaps; i++)
3356 {
3357 switch (Face->charmaps[i]->encoding)
3358 {
3359 case FT_ENCODING_UNICODE:
3360 case FT_ENCODING_APPLE_ROMAN:
3361 fs.fsCsb[0] |= FS_LATIN1;
3362 break;
3363 case FT_ENCODING_MS_SYMBOL:
3364 fs.fsCsb[0] |= FS_SYMBOL;
3365 break;
3366 default:
3367 break;
3368 }
3369 }
3370 }
3371 if (lpSig)
3372 {
3373 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
3374 }
3375
3376 RtlGetDefaultCodePage(&usACP, &usOEM);
3377 cp = usACP;
3378
3379 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
3380 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
3381 {
3382 DPRINT("Hit 1\n");
3383 Ret = csi.ciCharset;
3384 goto Exit;
3385 }
3386
3387 for (i = 0; i < MAXTCIINDEX; i++)
3388 {
3389 fs0 = 1L << i;
3390 if (fs.fsCsb[0] & fs0)
3391 {
3392 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
3393 {
3394 // *cp = csi.ciACP;
3395 DPRINT("Hit 2\n");
3396 Ret = csi.ciCharset;
3397 goto Exit;
3398 }
3399 else
3400 DPRINT1("TCI failing on %x\n", fs0);
3401 }
3402 }
3403 Exit:
3404 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
3405 return (MAKELONG(csi.ciACP, csi.ciCharset));
3406 }
3407
3408
3409 DWORD
3410 FASTCALL
3411 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
3412 {
3413 DWORD size = 0;
3414 DWORD num_ranges = 0;
3415 FT_Face face = Font->SharedFace->Face;
3416
3417 if (face->charmap->encoding == FT_ENCODING_UNICODE)
3418 {
3419 FT_UInt glyph_code = 0;
3420 FT_ULong char_code, char_code_prev;
3421
3422 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
3423
3424 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3425 face->num_glyphs, glyph_code, char_code);
3426
3427 if (!glyph_code) return 0;
3428
3429 if (glyphset)
3430 {
3431 glyphset->ranges[0].wcLow = (USHORT)char_code;
3432 glyphset->ranges[0].cGlyphs = 0;
3433 glyphset->cGlyphsSupported = 0;
3434 }
3435
3436 num_ranges = 1;
3437 while (glyph_code)
3438 {
3439 if (char_code < char_code_prev)
3440 {
3441 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
3442 return 0;
3443 }
3444 if (char_code - char_code_prev > 1)
3445 {
3446 num_ranges++;
3447 if (glyphset)
3448 {
3449 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
3450 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
3451 glyphset->cGlyphsSupported++;
3452 }
3453 }
3454 else if (glyphset)
3455 {
3456 glyphset->ranges[num_ranges - 1].cGlyphs++;
3457 glyphset->cGlyphsSupported++;
3458 }
3459 char_code_prev = char_code;
3460 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
3461 }
3462 }
3463 else
3464 DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
3465
3466 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
3467 if (glyphset)
3468 {
3469 glyphset->cbThis = size;
3470 glyphset->cRanges = num_ranges;
3471 glyphset->flAccel = 0;
3472 }
3473 return size;
3474 }
3475
3476
3477 BOOL
3478 FASTCALL
3479 ftGdiGetTextMetricsW(
3480 HDC hDC,
3481 PTMW_INTERNAL ptmwi)
3482 {
3483 PDC dc;
3484 PDC_ATTR pdcattr;
3485 PTEXTOBJ TextObj;
3486 PFONTGDI FontGDI;
3487 FT_Face Face;
3488 TT_OS2 *pOS2;
3489 TT_HoriHeader *pHori;
3490 FT_WinFNT_HeaderRec Win;
3491 ULONG Error;
3492 NTSTATUS Status = STATUS_SUCCESS;
3493 LOGFONTW *plf;
3494
3495 if (!ptmwi)
3496 {
3497 EngSetLastError(STATUS_INVALID_PARAMETER);
3498 return FALSE;
3499 }
3500
3501 if (!(dc = DC_LockDc(hDC)))
3502 {
3503 EngSetLastError(ERROR_INVALID_HANDLE);
3504 return FALSE;
3505 }
3506 pdcattr = dc->pdcattr;
3507 TextObj = RealizeFontInit(pdcattr->hlfntNew);
3508 if (NULL != TextObj)
3509 {
3510 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3511 FontGDI = ObjToGDI(TextObj->Font, FONT);
3512
3513 Face = FontGDI->SharedFace->Face;
3514 IntLockFreeType;
3515 Error = IntRequestFontSize(dc, Face, plf->lfWidth, plf->lfHeight);
3516 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
3517 IntUnLockFreeType;
3518 if (0 != Error)
3519 {
3520 DPRINT1("Error in setting pixel sizes: %u\n", Error);
3521 Status = STATUS_UNSUCCESSFUL;
3522 }
3523 else
3524 {
3525 FT_Face Face = FontGDI->SharedFace->Face;
3526 Status = STATUS_SUCCESS;
3527
3528 IntLockFreeType;
3529 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3530 if (NULL == pOS2)
3531 {
3532 DPRINT1("Can't find OS/2 table - not TT font?\n");
3533 Status = STATUS_INTERNAL_ERROR;
3534 }
3535
3536 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
3537 if (NULL == pHori)
3538 {
3539 DPRINT1("Can't find HHEA table - not TT font?\n");
3540 Status = STATUS_INTERNAL_ERROR;
3541 }
3542
3543 Error = FT_Get_WinFNT_Header(Face, &Win);
3544
3545 IntUnLockFreeType;
3546
3547 if (NT_SUCCESS(Status))
3548 {
3549 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
3550
3551 /* FIXME: Fill Diff member */
3552 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
3553 }
3554 }
3555 TEXTOBJ_UnlockText(TextObj);
3556 }
3557 else
3558 {
3559 Status = STATUS_INVALID_HANDLE;
3560 }
3561 DC_UnlockDc(dc);
3562
3563 if (!NT_SUCCESS(Status))
3564 {
3565 SetLastNtError(Status);
3566 return FALSE;
3567 }
3568 return TRUE;
3569 }
3570
3571 DWORD
3572 FASTCALL
3573 ftGdiGetFontData(
3574 PFONTGDI FontGdi,
3575 DWORD Table,
3576 DWORD Offset,
3577 PVOID Buffer,
3578 DWORD Size)
3579 {
3580 DWORD Result = GDI_ERROR;
3581 FT_Face Face = FontGdi->SharedFace->Face;
3582
3583 IntLockFreeType;
3584
3585 if (FT_IS_SFNT(Face))
3586 {
3587 if (Table)
3588 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
3589 (Table << 8 & 0xFF0000);
3590
3591 if (!Buffer) Size = 0;
3592
3593 if (Buffer && Size)
3594 {
3595 FT_Error Error;
3596 FT_ULong Needed = 0;
3597
3598 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
3599
3600 if ( !Error && Needed < Size) Size = Needed;
3601 }
3602 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
3603 Result = Size;
3604 }
3605
3606 IntUnLockFreeType;
3607
3608 return Result;
3609 }
3610
3611 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
3612 static UINT FASTCALL
3613 GetFontPenalty(LOGFONTW * LogFont,
3614 PUNICODE_STRING RequestedNameW,
3615 PUNICODE_STRING ActualNameW,
3616 PUNICODE_STRING FullFaceNameW,
3617 BYTE RequestedCharSet,
3618 PFONTGDI FontGDI<