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