[WIN32SS] Implement NtGdiAddFontMemResourceEx and NtGdiRemoveFontMemResourceEx. CORE...
[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 LoadFont.pFileName = NULL;
1074 LoadFont.Buffer = Buffer;
1075 LoadFont.BufferSize = dwSize;
1076 LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
1077 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1078 LoadFont.IsTrueType = FALSE;
1079 LoadFont.PrivateEntry = NULL;
1080 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1081
1082 RtlFreeUnicodeString(&LoadFont.RegValueName);
1083
1084 *pNumAdded = FontCount;
1085 if (FontCount > 0)
1086 {
1087 EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
1088 if (EntryCollection)
1089 {
1090 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1091 EntryCollection->Entry = LoadFont.PrivateEntry;
1092 IntLockProcessPrivateFonts(Win32Process);
1093 EntryCollection->Handle = ++Win32Process->PrivateMemFontHandleCount;
1094 InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
1095 IntUnLockProcessPrivateFonts(Win32Process);
1096 Ret = (HANDLE)EntryCollection->Handle;
1097 }
1098 }
1099
1100 return Ret;
1101 }
1102
1103 // FIXME: Add RemoveFontResource
1104
1105 VOID FASTCALL
1106 IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
1107 {
1108 PLIST_ENTRY Entry;
1109 PFONT_ENTRY_MEM FontEntry;
1110
1111 while (!IsListEmpty(&Head->ListEntry))
1112 {
1113 Entry = RemoveHeadList(&Head->ListEntry);
1114 FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
1115
1116 // Delete FontEntry->Entry (FONT_ENTRY*)
1117 ExFreePoolWithTag(FontEntry, TAG_FONT);
1118 }
1119
1120 // Delete Head->Entry (FONT_ENTRY*)
1121 ExFreePoolWithTag(Head, TAG_FONT);
1122 }
1123
1124 BOOL FASTCALL
1125 IntGdiRemoveFontMemResource(HANDLE hMMFont)
1126 {
1127 PLIST_ENTRY Entry;
1128 PFONT_ENTRY_COLL_MEM CurrentEntry;
1129 PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
1130 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1131
1132 IntLockProcessPrivateFonts(Win32Process);
1133 Entry = Win32Process->PrivateMemFontListHead.Flink;
1134 while (Entry != &Win32Process->PrivateMemFontListHead)
1135 {
1136 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1137
1138 if (CurrentEntry->Handle == (UINT)hMMFont)
1139 {
1140 EntryCollection = CurrentEntry;
1141 RemoveEntryList(Entry);
1142 break;
1143 }
1144
1145 Entry = Entry->Flink;
1146 }
1147 IntUnLockProcessPrivateFonts(Win32Process);
1148
1149 if (EntryCollection)
1150 {
1151 IntGdiCleanupMemEntry(EntryCollection->Entry);
1152 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1153 return TRUE;
1154 }
1155 return FALSE;
1156 }
1157
1158
1159 BOOL FASTCALL
1160 IntIsFontRenderingEnabled(VOID)
1161 {
1162 BOOL Ret = RenderingEnabled;
1163 HDC hDC;
1164
1165 hDC = IntGetScreenDC();
1166 if (hDC)
1167 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
1168
1169 return Ret;
1170 }
1171
1172 VOID FASTCALL
1173 IntEnableFontRendering(BOOL Enable)
1174 {
1175 RenderingEnabled = Enable;
1176 }
1177
1178 FT_Render_Mode FASTCALL
1179 IntGetFontRenderMode(LOGFONTW *logfont)
1180 {
1181 switch (logfont->lfQuality)
1182 {
1183 case ANTIALIASED_QUALITY:
1184 case NONANTIALIASED_QUALITY:
1185 return FT_RENDER_MODE_MONO;
1186 case DRAFT_QUALITY:
1187 return FT_RENDER_MODE_LIGHT;
1188 /* case CLEARTYPE_QUALITY:
1189 return FT_RENDER_MODE_LCD; */
1190 }
1191 return FT_RENDER_MODE_NORMAL;
1192 }
1193
1194
1195 NTSTATUS FASTCALL
1196 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
1197 {
1198 PLFONT plfont;
1199 LOGFONTW *plf;
1200
1201 plfont = LFONT_AllocFontWithHandle();
1202 if (!plfont)
1203 {
1204 return STATUS_NO_MEMORY;
1205 }
1206
1207 ExInitializePushLock(&plfont->lock);
1208 *NewFont = plfont->BaseObject.hHmgr;
1209 plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
1210 RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
1211 if (lf->lfEscapement != lf->lfOrientation)
1212 {
1213 /* This should really depend on whether GM_ADVANCED is set */
1214 plf->lfOrientation = plf->lfEscapement;
1215 }
1216 LFONT_UnlockFont(plfont);
1217
1218 return STATUS_SUCCESS;
1219 }
1220
1221 /*************************************************************************
1222 * TranslateCharsetInfo
1223 *
1224 * Fills a CHARSETINFO structure for a character set, code page, or
1225 * font. This allows making the correspondance between different labelings
1226 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
1227 * of the same encoding.
1228 *
1229 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
1230 * only one codepage should be set in *Src.
1231 *
1232 * RETURNS
1233 * TRUE on success, FALSE on failure.
1234 *
1235 */
1236 static BOOLEAN APIENTRY
1237 IntTranslateCharsetInfo(PDWORD Src, /* [in]
1238 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
1239 if flags == TCI_SRCCHARSET: a character set value
1240 if flags == TCI_SRCCODEPAGE: a code page value */
1241 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
1242 DWORD Flags /* [in] determines interpretation of lpSrc */)
1243 {
1244 int Index = 0;
1245
1246 switch (Flags)
1247 {
1248 case TCI_SRCFONTSIG:
1249 while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
1250 {
1251 Index++;
1252 }
1253 break;
1254 case TCI_SRCCODEPAGE:
1255 while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciACP)
1256 {
1257 Index++;
1258 }
1259 break;
1260 case TCI_SRCCHARSET:
1261 while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciCharset)
1262 {
1263 Index++;
1264 }
1265 break;
1266 default:
1267 return FALSE;
1268 }
1269
1270 if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == FontTci[Index].ciCharset)
1271 {
1272 return FALSE;
1273 }
1274
1275 RtlCopyMemory(Cs, &FontTci[Index], sizeof(CHARSETINFO));
1276
1277 return TRUE;
1278 }
1279
1280
1281 static BOOL face_has_symbol_charmap(FT_Face ft_face)
1282 {
1283 int i;
1284
1285 for(i = 0; i < ft_face->num_charmaps; i++)
1286 {
1287 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
1288 return TRUE;
1289 }
1290 return FALSE;
1291 }
1292
1293
1294 static void FASTCALL
1295 FillTMEx(TEXTMETRICW *TM, PFONTGDI FontGDI,
1296 TT_OS2 *pOS2, TT_HoriHeader *pHori,
1297 FT_WinFNT_HeaderRec *pFNT, BOOL RealFont)
1298 {
1299 FT_Fixed XScale, YScale;
1300 int Ascent, Descent;
1301 FT_Face Face = FontGDI->SharedFace->Face;
1302
1303 XScale = Face->size->metrics.x_scale;
1304 YScale = Face->size->metrics.y_scale;
1305
1306 if (pFNT)
1307 {
1308 TM->tmHeight = pFNT->pixel_height;
1309 TM->tmAscent = pFNT->ascent;
1310 TM->tmDescent = TM->tmHeight - TM->tmAscent;
1311 TM->tmInternalLeading = pFNT->internal_leading;
1312 TM->tmExternalLeading = pFNT->external_leading;
1313 TM->tmAveCharWidth = pFNT->avg_width;
1314 TM->tmMaxCharWidth = pFNT->max_width;
1315 TM->tmOverhang = 0;
1316 TM->tmDigitizedAspectX = pFNT->horizontal_resolution;
1317 TM->tmDigitizedAspectY = pFNT->vertical_resolution;
1318 TM->tmFirstChar = pFNT->first_char;
1319 TM->tmLastChar = pFNT->last_char;
1320 TM->tmDefaultChar = pFNT->default_char + pFNT->first_char;
1321 TM->tmBreakChar = pFNT->break_char + pFNT->first_char;
1322 TM->tmPitchAndFamily = pFNT->pitch_and_family;
1323 if (RealFont)
1324 {
1325 TM->tmWeight = FontGDI->OriginalWeight;
1326 TM->tmItalic = FontGDI->OriginalItalic;
1327 TM->tmUnderlined = pFNT->underline;
1328 TM->tmStruckOut = pFNT->strike_out;
1329 TM->tmCharSet = pFNT->charset;
1330 }
1331 else
1332 {
1333 TM->tmWeight = FontGDI->RequestWeight;
1334 TM->tmItalic = FontGDI->RequestItalic;
1335 TM->tmUnderlined = FontGDI->RequestUnderline;
1336 TM->tmStruckOut = FontGDI->RequestStrikeOut;
1337 TM->tmCharSet = FontGDI->CharSet;
1338 }
1339 return;
1340 }
1341
1342 if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
1343 {
1344 Ascent = pHori->Ascender;
1345 Descent = -pHori->Descender;
1346 }
1347 else
1348 {
1349 Ascent = pOS2->usWinAscent;
1350 Descent = pOS2->usWinDescent;
1351 }
1352
1353 #if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */
1354 TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
1355 TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
1356 #else /* This (ros) code was previously affected by a FreeType bug, but it works now */
1357 TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* Units above baseline */
1358 TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* Units below baseline */
1359 #endif
1360 TM->tmInternalLeading = (FT_MulFix(Ascent + Descent - Face->units_per_EM, YScale) + 32) >> 6;
1361
1362 TM->tmHeight = TM->tmAscent + TM->tmDescent;
1363
1364 /* MSDN says:
1365 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1366 */
1367 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
1368 - ((Ascent + Descent)
1369 - (pHori->Ascender - pHori->Descender)),
1370 YScale) + 32) >> 6);
1371
1372 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
1373 if (TM->tmAveCharWidth == 0)
1374 {
1375 TM->tmAveCharWidth = 1;
1376 }
1377
1378 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
1379 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
1380
1381 if (RealFont)
1382 {
1383 TM->tmWeight = FontGDI->OriginalWeight;
1384 }
1385 else
1386 {
1387 if (FontGDI->OriginalWeight != FW_DONTCARE &&
1388 FontGDI->OriginalWeight != FW_NORMAL)
1389 {
1390 TM->tmWeight = FontGDI->OriginalWeight;
1391 }
1392 else
1393 {
1394 TM->tmWeight = FontGDI->RequestWeight;
1395 }
1396 }
1397
1398 TM->tmOverhang = 0;
1399 TM->tmDigitizedAspectX = 96;
1400 TM->tmDigitizedAspectY = 96;
1401 if (face_has_symbol_charmap(Face) ||
1402 (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
1403 {
1404 USHORT cpOEM, cpAnsi;
1405
1406 EngGetCurrentCodePage(&cpOEM, &cpAnsi);
1407 TM->tmFirstChar = 0;
1408 switch(cpAnsi)
1409 {
1410 case 1257: /* Baltic */
1411 TM->tmLastChar = 0xf8fd;
1412 break;
1413 default:
1414 TM->tmLastChar = 0xf0ff;
1415 }
1416 TM->tmBreakChar = 0x20;
1417 TM->tmDefaultChar = 0x1f;
1418 }
1419 else
1420 {
1421 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
1422 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
1423
1424 if(pOS2->usFirstCharIndex <= 1)
1425 TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
1426 else if (pOS2->usFirstCharIndex > 0xff)
1427 TM->tmBreakChar = 0x20;
1428 else
1429 TM->tmBreakChar = pOS2->usFirstCharIndex;
1430 TM->tmDefaultChar = TM->tmBreakChar - 1;
1431 }
1432
1433 if (RealFont)
1434 {
1435 TM->tmItalic = FontGDI->OriginalItalic;
1436 TM->tmUnderlined = FALSE;
1437 TM->tmStruckOut = FALSE;
1438 }
1439 else
1440 {
1441 if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
1442 {
1443 TM->tmItalic = 0xFF;
1444 }
1445 else
1446 {
1447 TM->tmItalic = 0;
1448 }
1449 TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
1450 TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
1451 }
1452
1453 if (!FT_IS_FIXED_WIDTH(Face))
1454 {
1455 switch (pOS2->panose[PAN_PROPORTION_INDEX])
1456 {
1457 case PAN_PROP_MONOSPACED:
1458 TM->tmPitchAndFamily = 0;
1459 break;
1460 default:
1461 TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH;
1462 break;
1463 }
1464 }
1465 else
1466 {
1467 TM->tmPitchAndFamily = 0;
1468 }
1469
1470 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
1471 {
1472 case PAN_FAMILY_SCRIPT:
1473 TM->tmPitchAndFamily |= FF_SCRIPT;
1474 break;
1475 case PAN_FAMILY_DECORATIVE:
1476 TM->tmPitchAndFamily |= FF_DECORATIVE;
1477 break;
1478
1479 case PAN_ANY:
1480 case PAN_NO_FIT:
1481 case PAN_FAMILY_TEXT_DISPLAY:
1482 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
1483 /* Which is clearly not what the panose spec says. */
1484 if (TM->tmPitchAndFamily == 0) /* Fixed */
1485 {
1486 TM->tmPitchAndFamily = FF_MODERN;
1487 }
1488 else
1489 {
1490 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
1491 {
1492 case PAN_ANY:
1493 case PAN_NO_FIT:
1494 default:
1495 TM->tmPitchAndFamily |= FF_DONTCARE;
1496 break;
1497
1498 case PAN_SERIF_COVE:
1499 case PAN_SERIF_OBTUSE_COVE:
1500 case PAN_SERIF_SQUARE_COVE:
1501 case PAN_SERIF_OBTUSE_SQUARE_COVE:
1502 case PAN_SERIF_SQUARE:
1503 case PAN_SERIF_THIN:
1504 case PAN_SERIF_BONE:
1505 case PAN_SERIF_EXAGGERATED:
1506 case PAN_SERIF_TRIANGLE:
1507 TM->tmPitchAndFamily |= FF_ROMAN;
1508 break;
1509
1510 case PAN_SERIF_NORMAL_SANS:
1511 case PAN_SERIF_OBTUSE_SANS:
1512 case PAN_SERIF_PERP_SANS:
1513 case PAN_SERIF_FLARED:
1514 case PAN_SERIF_ROUNDED:
1515 TM->tmPitchAndFamily |= FF_SWISS;
1516 break;
1517 }
1518 }
1519 break;
1520 default:
1521 TM->tmPitchAndFamily |= FF_DONTCARE;
1522 }
1523
1524 if (FT_IS_SCALABLE(Face))
1525 {
1526 TM->tmPitchAndFamily |= TMPF_VECTOR;
1527 }
1528 if (FT_IS_SFNT(Face))
1529 {
1530 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
1531 }
1532
1533 TM->tmCharSet = FontGDI->CharSet;
1534 }
1535
1536 static void FASTCALL
1537 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
1538 TT_OS2 *pOS2, TT_HoriHeader *pHori,
1539 FT_WinFNT_HeaderRec *pFNT)
1540 {
1541 FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
1542 }
1543
1544 /*************************************************************
1545 * IntGetOutlineTextMetrics
1546 *
1547 */
1548 INT FASTCALL
1549 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
1550 UINT Size,
1551 OUTLINETEXTMETRICW *Otm)
1552 {
1553 unsigned Needed;
1554 TT_OS2 *pOS2;
1555 TT_HoriHeader *pHori;
1556 TT_Postscript *pPost;
1557 FT_Fixed XScale, YScale;
1558 ANSI_STRING FamilyNameA, StyleNameA;
1559 UNICODE_STRING FamilyNameW, StyleNameW, Regular;
1560 FT_WinFNT_HeaderRec Win;
1561 FT_Error Error;
1562 char *Cp;
1563 NTSTATUS status;
1564 FT_Face Face = FontGDI->SharedFace->Face;
1565
1566 Needed = sizeof(OUTLINETEXTMETRICW);
1567
1568 RtlInitAnsiString(&FamilyNameA, Face->family_name);
1569 status = RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
1570 if (!NT_SUCCESS(status))
1571 {
1572 return 0;
1573 }
1574
1575 RtlInitAnsiString(&StyleNameA, Face->style_name);
1576 status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
1577 if (!NT_SUCCESS(status))
1578 {
1579 RtlFreeUnicodeString(&FamilyNameW);
1580 return 0;
1581 }
1582
1583 /* These names should be read from the TT name table */
1584
1585 /* Length of otmpFamilyName */
1586 Needed += FamilyNameW.Length + sizeof(WCHAR);
1587
1588 RtlInitUnicodeString(&Regular, L"Regular");
1589 /* Length of otmpFaceName */
1590 if (RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
1591 {
1592 Needed += FamilyNameW.Length + sizeof(WCHAR); /* Just the family name */
1593 }
1594 else
1595 {
1596 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
1597 }
1598
1599 /* Length of otmpStyleName */
1600 Needed += StyleNameW.Length + sizeof(WCHAR);
1601
1602 /* Length of otmpFullName */
1603 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
1604
1605 if (Size < Needed)
1606 {
1607 RtlFreeUnicodeString(&FamilyNameW);
1608 RtlFreeUnicodeString(&StyleNameW);
1609 return Needed;
1610 }
1611
1612 XScale = Face->size->metrics.x_scale;
1613 YScale = Face->size->metrics.y_scale;
1614
1615 IntLockFreeType;
1616 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
1617 if (NULL == pOS2)
1618 {
1619 IntUnLockFreeType;
1620 DPRINT1("Can't find OS/2 table - not TT font?\n");
1621 RtlFreeUnicodeString(&StyleNameW);
1622 RtlFreeUnicodeString(&FamilyNameW);
1623 return 0;
1624 }
1625
1626 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
1627 if (NULL == pHori)
1628 {
1629 IntUnLockFreeType;
1630 DPRINT1("Can't find HHEA table - not TT font?\n");
1631 RtlFreeUnicodeString(&StyleNameW);
1632 RtlFreeUnicodeString(&FamilyNameW);
1633 return 0;
1634 }
1635
1636 pPost = FT_Get_Sfnt_Table(Face, ft_sfnt_post); /* We can live with this failing */
1637
1638 Error = FT_Get_WinFNT_Header(Face , &Win);
1639
1640 Otm->otmSize = Needed;
1641
1642 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
1643
1644 Otm->otmFiller = 0;
1645 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1646 Otm->otmfsSelection = pOS2->fsSelection;
1647 Otm->otmfsType = pOS2->fsType;
1648 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1649 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1650 Otm->otmItalicAngle = 0; /* POST table */
1651 Otm->otmEMSquare = Face->units_per_EM;
1652 Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
1653 Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
1654 Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
1655 Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
1656 Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
1657 Otm->otmrcFontBox.left = (FT_MulFix(Face->bbox.xMin, XScale) + 32) >> 6;
1658 Otm->otmrcFontBox.right = (FT_MulFix(Face->bbox.xMax, XScale) + 32) >> 6;
1659 Otm->otmrcFontBox.top = (FT_MulFix(Face->bbox.yMax, YScale) + 32) >> 6;
1660 Otm->otmrcFontBox.bottom = (FT_MulFix(Face->bbox.yMin, YScale) + 32) >> 6;
1661 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
1662 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
1663 Otm->otmMacLineGap = Otm->otmLineGap;
1664 Otm->otmusMinimumPPEM = 0; /* TT Header */
1665 Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
1666 Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
1667 Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
1668 Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
1669 Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
1670 Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
1671 Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
1672 Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
1673 Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
1674 Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
1675 if (!pPost)
1676 {
1677 Otm->otmsUnderscoreSize = 0;
1678 Otm->otmsUnderscorePosition = 0;
1679 }
1680 else
1681 {
1682 Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
1683 Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
1684 }
1685
1686 IntUnLockFreeType;
1687
1688 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1689 Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
1690 Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
1691 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1692 Cp += FamilyNameW.Length + sizeof(WCHAR);
1693 Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
1694 wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
1695 Cp += StyleNameW.Length + sizeof(WCHAR);
1696 Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
1697 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1698 if (!RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
1699 {
1700 wcscat((WCHAR*) Cp, L" ");
1701 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
1702 Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
1703 }
1704 else
1705 {
1706 Cp += FamilyNameW.Length + sizeof(WCHAR);
1707 }
1708 Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
1709 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1710 wcscat((WCHAR*) Cp, L" ");
1711 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
1712
1713 RtlFreeUnicodeString(&StyleNameW);
1714 RtlFreeUnicodeString(&FamilyNameW);
1715
1716 return Needed;
1717 }
1718
1719 static PFONTGDI FASTCALL
1720 FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
1721 {
1722 PLIST_ENTRY Entry;
1723 PFONT_ENTRY CurrentEntry;
1724 ANSI_STRING EntryFaceNameA;
1725 UNICODE_STRING EntryFaceNameW;
1726 FONTGDI *FontGDI;
1727 NTSTATUS status;
1728
1729 Entry = Head->Flink;
1730 while (Entry != Head)
1731 {
1732 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1733
1734 FontGDI = CurrentEntry->Font;
1735 ASSERT(FontGDI);
1736
1737 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
1738 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
1739 if (!NT_SUCCESS(status))
1740 {
1741 break;
1742 }
1743
1744 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
1745 {
1746 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
1747 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
1748 }
1749
1750 if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE))
1751 {
1752 RtlFreeUnicodeString(&EntryFaceNameW);
1753 return FontGDI;
1754 }
1755
1756 RtlFreeUnicodeString(&EntryFaceNameW);
1757 Entry = Entry->Flink;
1758 }
1759
1760 return NULL;
1761 }
1762
1763 static PFONTGDI FASTCALL
1764 FindFaceNameInLists(PUNICODE_STRING FaceName)
1765 {
1766 PPROCESSINFO Win32Process;
1767 PFONTGDI Font;
1768
1769 /* Search the process local list */
1770 Win32Process = PsGetCurrentProcessWin32Process();
1771 IntLockProcessPrivateFonts(Win32Process);
1772 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
1773 IntUnLockProcessPrivateFonts(Win32Process);
1774 if (NULL != Font)
1775 {
1776 return Font;
1777 }
1778
1779 /* Search the global list */
1780 IntLockGlobalFonts;
1781 Font = FindFaceNameInList(FaceName, &FontListHead);
1782 IntUnLockGlobalFonts;
1783
1784 return Font;
1785 }
1786
1787 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
1788 static BYTE
1789 CharSetFromLangID(LANGID LangID)
1790 {
1791 /* FIXME: Add more and fix if wrong */
1792 switch (PRIMARYLANGID(LangID))
1793 {
1794 case LANG_CHINESE:
1795 switch (SUBLANGID(LangID))
1796 {
1797 case SUBLANG_CHINESE_TRADITIONAL:
1798 return CHINESEBIG5_CHARSET;
1799 case SUBLANG_CHINESE_SIMPLIFIED:
1800 default:
1801 break;
1802 }
1803 return GB2312_CHARSET;
1804
1805 case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
1806 case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
1807 return EASTEUROPE_CHARSET;
1808
1809 case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
1810 case LANG_SERBIAN: case LANG_UKRAINIAN:
1811 return RUSSIAN_CHARSET;
1812
1813 case LANG_ARABIC: return ARABIC_CHARSET;
1814 case LANG_GREEK: return GREEK_CHARSET;
1815 case LANG_HEBREW: return HEBREW_CHARSET;
1816 case LANG_JAPANESE: return SHIFTJIS_CHARSET;
1817 case LANG_KOREAN: return JOHAB_CHARSET;
1818 case LANG_TURKISH: return TURKISH_CHARSET;
1819 case LANG_THAI: return THAI_CHARSET;
1820 case LANG_LATVIAN: return BALTIC_CHARSET;
1821 case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
1822
1823 case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
1824 case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
1825 case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
1826 case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
1827 case LANG_SWEDISH: default:
1828 return ANSI_CHARSET;
1829 }
1830 }
1831
1832 static void
1833 SwapEndian(LPVOID pvData, DWORD Size)
1834 {
1835 BYTE b, *pb = pvData;
1836 Size /= 2;
1837 while (Size-- > 0)
1838 {
1839 b = pb[0];
1840 pb[0] = pb[1];
1841 pb[1] = b;
1842 ++pb; ++pb;
1843 }
1844 }
1845
1846 static NTSTATUS
1847 IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face)
1848 {
1849 FT_SfntName Name;
1850 INT i, Count;
1851 WCHAR Buf[LF_FACESIZE];
1852 NTSTATUS Status = STATUS_NOT_FOUND;
1853
1854 RtlInitUnicodeString(pLocalNameW, NULL);
1855
1856 Count = FT_Get_Sfnt_Name_Count(Face);
1857 for (i = 0; i < Count; ++i)
1858 {
1859 FT_Get_Sfnt_Name(Face, i, &Name);
1860 if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
1861 Name.encoding_id != TT_MS_ID_UNICODE_CS)
1862 {
1863 continue; /* not Microsoft Unicode name */
1864 }
1865
1866 if (Name.name_id != TT_NAME_ID_FONT_FAMILY ||
1867 Name.string == NULL || Name.string_len == 0 ||
1868 (Name.string[0] == 0 && Name.string[1] == 0))
1869 {
1870 continue; /* not family name */
1871 }
1872
1873 if (sizeof(Buf) < Name.string_len + sizeof(UNICODE_NULL))
1874 {
1875 continue; /* name too long */
1876 }
1877
1878 /* NOTE: Name.string is not null-terminated */
1879 RtlCopyMemory(Buf, Name.string, Name.string_len);
1880 Buf[Name.string_len / sizeof(WCHAR)] = UNICODE_NULL;
1881
1882 /* Convert UTF-16 big endian to little endian */
1883 SwapEndian(Buf, Name.string_len);
1884 #if 0
1885 DPRINT("IntGetFontLocalizedName: %S (%d)\n", Buf, Name.string_len);
1886 #endif
1887
1888 Status = RtlCreateUnicodeString(pLocalNameW, Buf);
1889 break;
1890 }
1891
1892 return Status;
1893 }
1894
1895 static void FASTCALL
1896 FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
1897 {
1898 ANSI_STRING StyleA;
1899 UNICODE_STRING StyleW;
1900 TT_OS2 *pOS2;
1901 FONTSIGNATURE fs;
1902 CHARSETINFO CharSetInfo;
1903 unsigned i, Size;
1904 OUTLINETEXTMETRICW *Otm;
1905 LOGFONTW *Lf;
1906 TEXTMETRICW *TM;
1907 NEWTEXTMETRICW *Ntm;
1908 DWORD fs0;
1909 NTSTATUS status;
1910 FT_Face Face = FontGDI->SharedFace->Face;
1911
1912 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
1913 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
1914 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
1915 if (!Otm)
1916 {
1917 return;
1918 }
1919 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
1920
1921 Lf = &Info->EnumLogFontEx.elfLogFont;
1922 TM = &Otm->otmTextMetrics;
1923
1924 Lf->lfHeight = TM->tmHeight;
1925 Lf->lfWidth = TM->tmAveCharWidth;
1926 Lf->lfWeight = TM->tmWeight;
1927 Lf->lfItalic = TM->tmItalic;
1928 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
1929 Lf->lfCharSet = TM->tmCharSet;
1930 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
1931 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
1932 Lf->lfQuality = PROOF_QUALITY;
1933
1934 Ntm = &Info->NewTextMetricEx.ntmTm;
1935 Ntm->tmHeight = TM->tmHeight;
1936 Ntm->tmAscent = TM->tmAscent;
1937 Ntm->tmDescent = TM->tmDescent;
1938 Ntm->tmInternalLeading = TM->tmInternalLeading;
1939 Ntm->tmExternalLeading = TM->tmExternalLeading;
1940 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
1941 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
1942 Ntm->tmWeight = TM->tmWeight;
1943 Ntm->tmOverhang = TM->tmOverhang;
1944 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
1945 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
1946 Ntm->tmFirstChar = TM->tmFirstChar;
1947 Ntm->tmLastChar = TM->tmLastChar;
1948 Ntm->tmDefaultChar = TM->tmDefaultChar;
1949 Ntm->tmBreakChar = TM->tmBreakChar;
1950 Ntm->tmItalic = TM->tmItalic;
1951 Ntm->tmUnderlined = TM->tmUnderlined;
1952 Ntm->tmStruckOut = TM->tmStruckOut;
1953 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
1954 Ntm->tmCharSet = TM->tmCharSet;
1955 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
1956
1957 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
1958
1959 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
1960
1961 Ntm->ntmSizeEM = Otm->otmEMSquare;
1962 Ntm->ntmCellHeight = Otm->otmEMSquare;
1963 Ntm->ntmAvgWidth = 0;
1964
1965 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
1966 ? TRUETYPE_FONTTYPE : 0);
1967
1968 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
1969 Info->FontType |= RASTER_FONTTYPE;
1970
1971 ExFreePoolWithTag(Otm, GDITAG_TEXT);
1972
1973 /* try the localized name */
1974 status = STATUS_UNSUCCESSFUL;
1975 if (CharSetFromLangID(gusLanguageID) == FontGDI->CharSet)
1976 {
1977 /* get localized name */
1978 UNICODE_STRING LocalNameW;
1979 status = IntGetFontLocalizedName(&LocalNameW, Face);
1980 if (NT_SUCCESS(status))
1981 {
1982 /* store it */
1983 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
1984 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
1985 LocalNameW.Buffer);
1986 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
1987 sizeof(Info->EnumLogFontEx.elfFullName),
1988 LocalNameW.Buffer);
1989 }
1990 RtlFreeUnicodeString(&LocalNameW);
1991 }
1992
1993 /* if localized name was unavailable */
1994 if (!NT_SUCCESS(status))
1995 {
1996 /* store English name */
1997 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
1998 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
1999 FaceName);
2000 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2001 sizeof(Info->EnumLogFontEx.elfFullName),
2002 FaceName);
2003 }
2004
2005 RtlInitAnsiString(&StyleA, Face->style_name);
2006 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
2007 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
2008 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
2009 if (!NT_SUCCESS(status))
2010 {
2011 return;
2012 }
2013 if (StyleW.Length)
2014 {
2015 if (wcslen(Info->EnumLogFontEx.elfFullName) +
2016 StyleW.Length / sizeof(WCHAR) + 1 <=
2017 sizeof(Info->EnumLogFontEx.elfFullName))
2018 {
2019 wcscat(Info->EnumLogFontEx.elfFullName, L" ");
2020 wcscat(Info->EnumLogFontEx.elfFullName, StyleW.Buffer);
2021 }
2022 }
2023
2024 Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
2025 Info->EnumLogFontEx.elfScript[0] = L'\0';
2026 IntLockFreeType;
2027 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2028
2029 if (!pOS2)
2030 {
2031 IntUnLockFreeType;
2032 return;
2033 }
2034
2035 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2036 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2037 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2038 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2039 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2040 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2041
2042 if (0 == pOS2->version)
2043 {
2044 FT_UInt Dummy;
2045
2046 if (FT_Get_First_Char(Face, &Dummy) < 0x100)
2047 fs.fsCsb[0] |= FS_LATIN1;
2048 else
2049 fs.fsCsb[0] |= FS_SYMBOL;
2050 }
2051 IntUnLockFreeType;
2052
2053 if (fs.fsCsb[0] == 0)
2054 {
2055 /* Let's see if we can find any interesting cmaps */
2056 for (i = 0; i < (UINT)Face->num_charmaps; i++)
2057 {
2058 switch (Face->charmaps[i]->encoding)
2059 {
2060 case FT_ENCODING_UNICODE:
2061 case FT_ENCODING_APPLE_ROMAN:
2062 fs.fsCsb[0] |= FS_LATIN1;
2063 break;
2064 case FT_ENCODING_MS_SYMBOL:
2065 fs.fsCsb[0] |= FS_SYMBOL;
2066 break;
2067 default:
2068 break;
2069 }
2070 }
2071 }
2072
2073 for (i = 0; i < MAXTCIINDEX; i++)
2074 {
2075 fs0 = 1L << i;
2076 if (fs.fsCsb[0] & fs0)
2077 {
2078 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
2079 {
2080 CharSetInfo.ciCharset = DEFAULT_CHARSET;
2081 }
2082 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
2083 {
2084 Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
2085 if (ElfScripts[i])
2086 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
2087 else
2088 {
2089 DPRINT1("Unknown elfscript for bit %u\n", i);
2090 }
2091 }
2092 }
2093 }
2094 Info->NewTextMetricEx.ntmFontSig = fs;
2095 }
2096
2097 static int FASTCALL
2098 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
2099 {
2100 DWORD i;
2101 UNICODE_STRING InfoFaceName;
2102
2103 for (i = 0; i < InfoEntries; i++)
2104 {
2105 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
2106 if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE))
2107 {
2108 return i;
2109 }
2110 }
2111
2112 return -1;
2113 }
2114
2115 static BOOLEAN FASTCALL
2116 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
2117 PFONTFAMILYINFO Info, DWORD InfoEntries)
2118 {
2119 UNICODE_STRING LogFontFaceName;
2120
2121 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
2122 if (0 != LogFontFaceName.Length &&
2123 !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE))
2124 {
2125 return FALSE;
2126 }
2127
2128 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
2129 }
2130
2131 static BOOLEAN FASTCALL
2132 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
2133 PFONTFAMILYINFO Info,
2134 DWORD *Count,
2135 DWORD Size,
2136 PLIST_ENTRY Head)
2137 {
2138 PLIST_ENTRY Entry;
2139 PFONT_ENTRY CurrentEntry;
2140 ANSI_STRING EntryFaceNameA;
2141 UNICODE_STRING EntryFaceNameW;
2142 FONTGDI *FontGDI;
2143 NTSTATUS status;
2144
2145 Entry = Head->Flink;
2146 while (Entry != Head)
2147 {
2148 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2149
2150 FontGDI = CurrentEntry->Font;
2151 ASSERT(FontGDI);
2152
2153 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
2154 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2155 if (!NT_SUCCESS(status))
2156 {
2157 return FALSE;
2158 }
2159
2160 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2161 {
2162 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2163 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2164 }
2165
2166 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
2167 {
2168 if (*Count < Size)
2169 {
2170 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
2171 }
2172 (*Count)++;
2173 }
2174 RtlFreeUnicodeString(&EntryFaceNameW);
2175 Entry = Entry->Flink;
2176 }
2177
2178 return TRUE;
2179 }
2180
2181 typedef struct FontFamilyInfoCallbackContext
2182 {
2183 LPLOGFONTW LogFont;
2184 PFONTFAMILYINFO Info;
2185 DWORD Count;
2186 DWORD Size;
2187 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
2188
2189 _Function_class_(RTL_QUERY_REGISTRY_ROUTINE)
2190 static NTSTATUS APIENTRY
2191 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
2192 IN PVOID ValueData, IN ULONG ValueLength,
2193 IN PVOID Context, IN PVOID EntryContext)
2194 {
2195 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
2196 UNICODE_STRING RegistryName, RegistryValue;
2197 int Existing;
2198 PFONTGDI FontGDI;
2199
2200 if (REG_SZ != ValueType)
2201 {
2202 return STATUS_SUCCESS;
2203 }
2204 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
2205 RtlInitUnicodeString(&RegistryName, ValueName);
2206
2207 /* Do we need to include this font family? */
2208 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
2209 min(InfoContext->Count, InfoContext->Size)))
2210 {
2211 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
2212 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
2213 min(InfoContext->Count, InfoContext->Size));
2214 if (0 <= Existing)
2215 {
2216 /* We already have the information about the "real" font. Just copy it */
2217 if (InfoContext->Count < InfoContext->Size)
2218 {
2219 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
2220 RtlStringCbCopyNW(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
2221 sizeof(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName),
2222 RegistryName.Buffer,
2223 RegistryName.Length);
2224 }
2225 InfoContext->Count++;
2226 return STATUS_SUCCESS;
2227 }
2228
2229 /* Try to find information about the "real" font */
2230 FontGDI = FindFaceNameInLists(&RegistryValue);
2231 if (NULL == FontGDI)
2232 {
2233 /* "Real" font not found, discard this registry entry */
2234 return STATUS_SUCCESS;
2235 }
2236
2237 /* Return info about the "real" font but with the name of the alias */
2238 if (InfoContext->Count < InfoContext->Size)
2239 {
2240 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
2241 RegistryName.Buffer, FontGDI);
2242 }
2243 InfoContext->Count++;
2244 return STATUS_SUCCESS;
2245 }
2246
2247 return STATUS_SUCCESS;
2248 }
2249
2250 static BOOLEAN FASTCALL
2251 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
2252 PFONTFAMILYINFO Info,
2253 DWORD *Count,
2254 DWORD Size)
2255 {
2256 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2257 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
2258 NTSTATUS Status;
2259
2260 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
2261 The real work is done in the registry callback function */
2262 Context.LogFont = LogFont;
2263 Context.Info = Info;
2264 Context.Count = *Count;
2265 Context.Size = Size;
2266
2267 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
2268 QueryTable[0].Flags = 0;
2269 QueryTable[0].Name = NULL;
2270 QueryTable[0].EntryContext = NULL;
2271 QueryTable[0].DefaultType = REG_NONE;
2272 QueryTable[0].DefaultData = NULL;
2273 QueryTable[0].DefaultLength = 0;
2274
2275 QueryTable[1].QueryRoutine = NULL;
2276 QueryTable[1].Name = NULL;
2277
2278 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2279 L"FontSubstitutes",
2280 QueryTable,
2281 &Context,
2282 NULL);
2283 if (NT_SUCCESS(Status))
2284 {
2285 *Count = Context.Count;
2286 }
2287
2288 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
2289 }
2290
2291 BOOL
2292 FASTCALL
2293 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
2294 {
2295 if ( lprs )
2296 {
2297 lprs->nSize = sizeof(RASTERIZER_STATUS);
2298 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
2299 lprs->nLanguageID = gusLanguageID;
2300 return TRUE;
2301 }
2302 EngSetLastError(ERROR_INVALID_PARAMETER);
2303 return FALSE;
2304 }
2305
2306 static
2307 BOOL
2308 SameScaleMatrix(
2309 PMATRIX pmx1,
2310 PMATRIX pmx2)
2311 {
2312 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
2313 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
2314 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
2315 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
2316 }
2317
2318 FT_BitmapGlyph APIENTRY
2319 ftGdiGlyphCacheGet(
2320 FT_Face Face,
2321 INT GlyphIndex,
2322 INT Height,
2323 PMATRIX pmx)
2324 {
2325 PLIST_ENTRY CurrentEntry;
2326 PFONT_CACHE_ENTRY FontEntry;
2327
2328 CurrentEntry = FontCacheListHead.Flink;
2329 while (CurrentEntry != &FontCacheListHead)
2330 {
2331 FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
2332 if ((FontEntry->Face == Face) &&
2333 (FontEntry->GlyphIndex == GlyphIndex) &&
2334 (FontEntry->Height == Height) &&
2335 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2336 break;
2337 CurrentEntry = CurrentEntry->Flink;
2338 }
2339
2340 if (CurrentEntry == &FontCacheListHead)
2341 {
2342 return NULL;
2343 }
2344
2345 RemoveEntryList(CurrentEntry);
2346 InsertHeadList(&FontCacheListHead, CurrentEntry);
2347 return FontEntry->BitmapGlyph;
2348 }
2349
2350 /* no cache */
2351 FT_BitmapGlyph APIENTRY
2352 ftGdiGlyphSet(
2353 FT_Face Face,
2354 FT_GlyphSlot GlyphSlot,
2355 FT_Render_Mode RenderMode)
2356 {
2357 FT_Glyph Glyph;
2358 INT error;
2359 FT_Bitmap AlignedBitmap;
2360 FT_BitmapGlyph BitmapGlyph;
2361
2362 error = FT_Get_Glyph(GlyphSlot, &Glyph);
2363 if (error)
2364 {
2365 DPRINT1("Failure getting glyph.\n");
2366 return NULL;
2367 }
2368
2369 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2370 if (error)
2371 {
2372 FT_Done_Glyph(Glyph);
2373 DPRINT1("Failure rendering glyph.\n");
2374 return NULL;
2375 }
2376
2377 BitmapGlyph = (FT_BitmapGlyph)Glyph;
2378 FT_Bitmap_New(&AlignedBitmap);
2379 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2380 {
2381 DPRINT1("Conversion failed\n");
2382 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2383 return NULL;
2384 }
2385
2386 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2387 BitmapGlyph->bitmap = AlignedBitmap;
2388
2389 return BitmapGlyph;
2390 }
2391
2392 FT_BitmapGlyph APIENTRY
2393 ftGdiGlyphCacheSet(
2394 FT_Face Face,
2395 INT GlyphIndex,
2396 INT Height,
2397 PMATRIX pmx,
2398 FT_GlyphSlot GlyphSlot,
2399 FT_Render_Mode RenderMode)
2400 {
2401 FT_Glyph GlyphCopy;
2402 INT error;
2403 PFONT_CACHE_ENTRY NewEntry;
2404 FT_Bitmap AlignedBitmap;
2405 FT_BitmapGlyph BitmapGlyph;
2406
2407 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2408 if (error)
2409 {
2410 DPRINT1("Failure caching glyph.\n");
2411 return NULL;
2412 };
2413
2414 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2415 if (error)
2416 {
2417 FT_Done_Glyph(GlyphCopy);
2418 DPRINT1("Failure rendering glyph.\n");
2419 return NULL;
2420 };
2421
2422 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
2423 if (!NewEntry)
2424 {
2425 DPRINT1("Alloc failure caching glyph.\n");
2426 FT_Done_Glyph(GlyphCopy);
2427 return NULL;
2428 }
2429
2430 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2431 FT_Bitmap_New(&AlignedBitmap);
2432 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2433 {
2434 DPRINT1("Conversion failed\n");
2435 ExFreePoolWithTag(NewEntry, TAG_FONT);
2436 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2437 return NULL;
2438 }
2439
2440 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2441 BitmapGlyph->bitmap = AlignedBitmap;
2442
2443 NewEntry->GlyphIndex = GlyphIndex;
2444 NewEntry->Face = Face;
2445 NewEntry->BitmapGlyph = BitmapGlyph;
2446 NewEntry->Height = Height;
2447 NewEntry->mxWorldToDevice = *pmx;
2448
2449 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
2450 if (FontCacheNumEntries++ > MAX_FONT_CACHE)
2451 {
2452 NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
2453 FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph);
2454 RemoveTailList(&FontCacheListHead);
2455 ExFreePoolWithTag(NewEntry, TAG_FONT);
2456 FontCacheNumEntries--;
2457 }
2458
2459 return BitmapGlyph;
2460 }
2461
2462
2463 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2464 {
2465 pt->x.value = vec->x >> 6;
2466 pt->x.fract = (vec->x & 0x3f) << 10;
2467 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2468 pt->y.value = vec->y >> 6;
2469 pt->y.fract = (vec->y & 0x3f) << 10;
2470 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2471 }
2472
2473 /*
2474 This function builds an FT_Fixed from a float. It puts the integer part
2475 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2476 It fails if the integer part of the float number is greater than SHORT_MAX.
2477 */
2478 static __inline FT_Fixed FT_FixedFromFloat(float f)
2479 {
2480 short value = f;
2481 unsigned short fract = (f - value) * 0xFFFF;
2482 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2483 }
2484
2485 /*
2486 This function builds an FT_Fixed from a FIXED. It simply put f.value
2487 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2488 */
2489 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2490 {
2491 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2492 }
2493
2494 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2495 {
2496 TTPOLYGONHEADER *pph;
2497 TTPOLYCURVE *ppc;
2498 int needed = 0, point = 0, contour, first_pt;
2499 unsigned int pph_start, cpfx;
2500 DWORD type;
2501
2502 for (contour = 0; contour < outline->n_contours; contour++)
2503 {
2504 /* Ignore contours containing one point */
2505 if (point == outline->contours[contour])
2506 {
2507 point++;
2508 continue;
2509 }
2510
2511 pph_start = needed;
2512 pph = (TTPOLYGONHEADER *)(buf + needed);
2513 first_pt = point;
2514 if (buf)
2515 {
2516 pph->dwType = TT_POLYGON_TYPE;
2517 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2518 }
2519 needed += sizeof(*pph);
2520 point++;
2521 while (point <= outline->contours[contour])
2522 {
2523 ppc = (TTPOLYCURVE *)(buf + needed);
2524 type = outline->tags[point] & FT_Curve_Tag_On ?
2525 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2526 cpfx = 0;
2527 do
2528 {
2529 if (buf)
2530 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2531 cpfx++;
2532 point++;
2533 } while (point <= outline->contours[contour] &&
2534 (outline->tags[point] & FT_Curve_Tag_On) ==
2535 (outline->tags[point-1] & FT_Curve_Tag_On));
2536 /* At the end of a contour Windows adds the start point, but
2537 only for Beziers */
2538 if (point > outline->contours[contour] &&
2539 !(outline->tags[point-1] & FT_Curve_Tag_On))
2540 {
2541 if (buf)
2542 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2543 cpfx++;
2544 }
2545 else if (point <= outline->contours[contour] &&
2546 outline->tags[point] & FT_Curve_Tag_On)
2547 {
2548 /* add closing pt for bezier */
2549 if (buf)
2550 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2551 cpfx++;
2552 point++;
2553 }
2554 if (buf)
2555 {
2556 ppc->wType = type;
2557 ppc->cpfx = cpfx;
2558 }
2559 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2560 }
2561 if (buf)
2562 pph->cb = needed - pph_start;
2563 }
2564 return needed;
2565 }
2566
2567 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2568 {
2569 /* Convert the quadratic Beziers to cubic Beziers.
2570 The parametric eqn for a cubic Bezier is, from PLRM:
2571 r(t) = at^3 + bt^2 + ct + r0
2572 with the control points:
2573 r1 = r0 + c/3
2574 r2 = r1 + (c + b)/3
2575 r3 = r0 + c + b + a
2576
2577 A quadratic Bezier has the form:
2578 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2579
2580 So equating powers of t leads to:
2581 r1 = 2/3 p1 + 1/3 p0
2582 r2 = 2/3 p1 + 1/3 p2
2583 and of course r0 = p0, r3 = p2
2584 */
2585 int contour, point = 0, first_pt;
2586 TTPOLYGONHEADER *pph;
2587 TTPOLYCURVE *ppc;
2588 DWORD pph_start, cpfx, type;
2589 FT_Vector cubic_control[4];
2590 unsigned int needed = 0;
2591
2592 for (contour = 0; contour < outline->n_contours; contour++)
2593 {
2594 pph_start = needed;
2595 pph = (TTPOLYGONHEADER *)(buf + needed);
2596 first_pt = point;
2597 if (buf)
2598 {
2599 pph->dwType = TT_POLYGON_TYPE;
2600 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2601 }
2602 needed += sizeof(*pph);
2603 point++;
2604 while (point <= outline->contours[contour])
2605 {
2606 ppc = (TTPOLYCURVE *)(buf + needed);
2607 type = outline->tags[point] & FT_Curve_Tag_On ?
2608 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2609 cpfx = 0;
2610 do
2611 {
2612 if (type == TT_PRIM_LINE)
2613 {
2614 if (buf)
2615 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2616 cpfx++;
2617 point++;
2618 }
2619 else
2620 {
2621 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2622 so cpfx = 3n */
2623
2624 /* FIXME: Possible optimization in endpoint calculation
2625 if there are two consecutive curves */
2626 cubic_control[0] = outline->points[point-1];
2627 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2628 {
2629 cubic_control[0].x += outline->points[point].x + 1;
2630 cubic_control[0].y += outline->points[point].y + 1;
2631 cubic_control[0].x >>= 1;
2632 cubic_control[0].y >>= 1;
2633 }
2634 if (point+1 > outline->contours[contour])
2635 cubic_control[3] = outline->points[first_pt];
2636 else
2637 {
2638 cubic_control[3] = outline->points[point+1];
2639 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2640 {
2641 cubic_control[3].x += outline->points[point].x + 1;
2642 cubic_control[3].y += outline->points[point].y + 1;
2643 cubic_control[3].x >>= 1;
2644 cubic_control[3].y >>= 1;
2645 }
2646 }
2647 /* r1 = 1/3 p0 + 2/3 p1
2648 r2 = 1/3 p2 + 2/3 p1 */
2649 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2650 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2651 cubic_control[2] = cubic_control[1];
2652 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2653 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2654 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2655 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2656 if (buf)
2657 {
2658 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2659 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2660 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2661 }
2662 cpfx += 3;
2663 point++;
2664 }
2665 } while (point <= outline->contours[contour] &&
2666 (outline->tags[point] & FT_Curve_Tag_On) ==
2667 (outline->tags[point-1] & FT_Curve_Tag_On));
2668 /* At the end of a contour Windows adds the start point,
2669 but only for Beziers and we've already done that.
2670 */
2671 if (point <= outline->contours[contour] &&
2672 outline->tags[point] & FT_Curve_Tag_On)
2673 {
2674 /* This is the closing pt of a bezier, but we've already
2675 added it, so just inc point and carry on */
2676 point++;
2677 }
2678 if (buf)
2679 {
2680 ppc->wType = type;
2681 ppc->cpfx = cpfx;
2682 }
2683 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2684 }
2685 if (buf)
2686 pph->cb = needed - pph_start;
2687 }
2688 return needed;
2689 }
2690
2691 static INT
2692 IntRequestFontSize(PDC dc, FT_Face face, LONG Width, LONG Height)
2693 {
2694 FT_Size_RequestRec req;
2695
2696 if (Width < 0)
2697 Width = -Width;
2698
2699 if (Height < 0)
2700 {
2701 Height = -Height;
2702 }
2703 if (Height == 0)
2704 {
2705 Height = dc->ppdev->devinfo.lfDefaultFont.lfHeight;
2706 }
2707 if (Height == 0)
2708 {
2709 Height = Width;
2710 }
2711
2712 if (Height < 1)
2713 Height = 1;
2714
2715 if (Width > 0xFFFFU)
2716 Width = 0xFFFFU;
2717 if (Height > 0xFFFFU)
2718 Height = 0xFFFFU;
2719
2720 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
2721 req.width = (FT_Long)(Width << 6);
2722 req.height = (FT_Long)(Height << 6);
2723 req.horiResolution = 0;
2724 req.vertResolution = 0;
2725 return FT_Request_Size(face, &req);
2726 }
2727
2728 BOOL
2729 FASTCALL
2730 TextIntUpdateSize(PDC dc,
2731 PTEXTOBJ TextObj,
2732 PFONTGDI FontGDI,
2733 BOOL bDoLock)
2734 {
2735 FT_Face face;
2736 INT error, n;
2737 FT_CharMap charmap, found;
2738 LOGFONTW *plf;
2739
2740 if (bDoLock)
2741 IntLockFreeType;
2742
2743 face = FontGDI->SharedFace->Face;
2744 if (face->charmap == NULL)
2745 {
2746 DPRINT("WARNING: No charmap selected!\n");
2747 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2748
2749 found = NULL;
2750 for (n = 0; n < face->num_charmaps; n++)
2751 {
2752 charmap = face->charmaps[n];
2753 DPRINT("Found charmap encoding: %i\n", charmap->encoding);
2754 if (charmap->encoding != 0)
2755 {
2756 found = charmap;
2757 break;
2758 }
2759 }
2760 if (!found)
2761 {
2762 DPRINT1("WARNING: Could not find desired charmap!\n");
2763 }
2764 else
2765 {
2766 error = FT_Set_Charmap(face, found);
2767 if (error)
2768 {
2769 DPRINT1("WARNING: Could not set the charmap!\n");
2770 }
2771 }
2772 }
2773
2774 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
2775
2776 error = IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
2777
2778 if (bDoLock)
2779 IntUnLockFreeType;
2780
2781 if (error)
2782 {
2783 DPRINT1("Error in setting pixel sizes: %d\n", error);
2784 return FALSE;
2785 }
2786
2787 return TRUE;
2788 }
2789
2790
2791 /*
2792 * Based on WineEngGetGlyphOutline
2793 *
2794 */
2795 ULONG
2796 FASTCALL
2797 ftGdiGetGlyphOutline(
2798 PDC dc,
2799 WCHAR wch,
2800 UINT iFormat,
2801 LPGLYPHMETRICS pgm,
2802 ULONG cjBuf,
2803 PVOID pvBuf,
2804 LPMAT2 pmat2,
2805 BOOL bIgnoreRotation)
2806 {
2807 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2808 PDC_ATTR pdcattr;
2809 PTEXTOBJ TextObj;
2810 PFONTGDI FontGDI;
2811 HFONT hFont = 0;
2812 GLYPHMETRICS gm;
2813 ULONG Size;
2814 FT_Face ft_face;
2815 FT_UInt glyph_index;
2816 DWORD width, height, pitch, needed = 0;
2817 FT_Bitmap ft_bitmap;
2818 FT_Error error;
2819 INT left, right, top = 0, bottom = 0;
2820 FT_Angle angle = 0;
2821 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2822 FLOAT eM11, widthRatio = 1.0;
2823 FT_Matrix transMat = identityMat;
2824 BOOL needsTransform = FALSE;
2825 INT orientation;
2826 LONG aveWidth;
2827 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
2828 OUTLINETEXTMETRICW *potm;
2829 XFORM xForm;
2830 LOGFONTW *plf;
2831
2832 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
2833 cjBuf, pvBuf, pmat2);
2834
2835 pdcattr = dc->pdcattr;
2836
2837 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
2838 eM11 = xForm.eM11;
2839
2840 hFont = pdcattr->hlfntNew;
2841 TextObj = RealizeFontInit(hFont);
2842
2843 if (!TextObj)
2844 {
2845 EngSetLastError(ERROR_INVALID_HANDLE);
2846 return GDI_ERROR;
2847 }
2848 FontGDI = ObjToGDI(TextObj->Font, FONT);
2849 ft_face = FontGDI->SharedFace->Face;
2850
2851 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
2852 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
2853 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
2854
2855 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2856 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2857 if (!potm)
2858 {
2859 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2860 TEXTOBJ_UnlockText(TextObj);
2861 return GDI_ERROR;
2862 }
2863 IntGetOutlineTextMetrics(FontGDI, Size, potm);
2864
2865 IntLockFreeType;
2866 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
2867 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
2868
2869 TEXTOBJ_UnlockText(TextObj);
2870
2871 if (iFormat & GGO_GLYPH_INDEX)
2872 {
2873 glyph_index = wch;
2874 iFormat &= ~GGO_GLYPH_INDEX;
2875 }
2876 else glyph_index = FT_Get_Char_Index(ft_face, wch);
2877
2878 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
2879 load_flags |= FT_LOAD_NO_BITMAP;
2880
2881 if (iFormat & GGO_UNHINTED)
2882 {
2883 load_flags |= FT_LOAD_NO_HINTING;
2884 iFormat &= ~GGO_UNHINTED;
2885 }
2886
2887 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
2888 if (error)
2889 {
2890 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
2891 IntUnLockFreeType;
2892 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
2893 return GDI_ERROR;
2894 }
2895 IntUnLockFreeType;
2896
2897 if (aveWidth && potm)
2898 {
2899 widthRatio = (FLOAT)aveWidth * eM11 /
2900 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
2901 }
2902
2903 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2904 right = (INT)((ft_face->glyph->metrics.horiBearingX +
2905 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2906
2907 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2908 lsb = left >> 6;
2909 bbx = (right - left) >> 6;
2910
2911 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
2912
2913 IntLockFreeType;
2914
2915 /* Scaling transform */
2916 /*if (aveWidth)*/
2917 {
2918
2919 FT_Matrix ftmatrix;
2920 FLOATOBJ efTemp;
2921
2922 PMATRIX pmx = DC_pmxWorldToDevice(dc);
2923
2924 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
2925 efTemp = pmx->efM11;
2926 FLOATOBJ_MulLong(&efTemp, 0x00010000);
2927 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
2928
2929 efTemp = pmx->efM12;
2930 FLOATOBJ_MulLong(&efTemp, 0x00010000);
2931 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
2932
2933 efTemp = pmx->efM21;
2934 FLOATOBJ_MulLong(&efTemp, 0x00010000);
2935 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
2936
2937 efTemp = pmx->efM22;
2938 FLOATOBJ_MulLong(&efTemp, 0x00010000);
2939 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
2940
2941 FT_Matrix_Multiply(&ftmatrix, &transMat);
2942 needsTransform = TRUE;
2943 }
2944
2945 /* Rotation transform */
2946 if (orientation)
2947 {
2948 FT_Matrix rotationMat;
2949 FT_Vector vecAngle;
2950 DPRINT("Rotation Trans!\n");
2951 angle = FT_FixedFromFloat((float)orientation / 10.0);
2952 FT_Vector_Unit(&vecAngle, angle);
2953 rotationMat.xx = vecAngle.x;
2954 rotationMat.xy = -vecAngle.y;
2955 rotationMat.yx = -rotationMat.xy;
2956 rotationMat.yy = rotationMat.xx;
2957 FT_Matrix_Multiply(&rotationMat, &transMat);
2958 needsTransform = TRUE;
2959 }
2960
2961 /* Extra transformation specified by caller */
2962 if (pmat2)
2963 {
2964 FT_Matrix extraMat;
2965 DPRINT("MAT2 Matrix Trans!\n");
2966 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
2967 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
2968 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
2969 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
2970 FT_Matrix_Multiply(&extraMat, &transMat);
2971 needsTransform = TRUE;
2972 }
2973
2974 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
2975
2976 if (!needsTransform)
2977 {
2978 DPRINT("No Need to be Transformed!\n");
2979 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2980 bottom = (ft_face->glyph->metrics.horiBearingY -
2981 ft_face->glyph->metrics.height) & -64;
2982 gm.gmCellIncX = adv;
2983 gm.gmCellIncY = 0;
2984 }
2985 else
2986 {
2987 INT xc, yc;
2988 FT_Vector vec;
2989 for (xc = 0; xc < 2; xc++)
2990 {
2991 for (yc = 0; yc < 2; yc++)
2992 {
2993 vec.x = (ft_face->glyph->metrics.horiBearingX +
2994 xc * ft_face->glyph->metrics.width);
2995 vec.y = ft_face->glyph->metrics.horiBearingY -
2996 yc * ft_face->glyph->metrics.height;
2997 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
2998 FT_Vector_Transform(&vec, &transMat);
2999 if (xc == 0 && yc == 0)
3000 {
3001 left = right = vec.x;
3002 top = bottom = vec.y;
3003 }
3004 else
3005 {
3006 if (vec.x < left) left = vec.x;
3007 else if (vec.x > right) right = vec.x;
3008 if (vec.y < bottom) bottom = vec.y;
3009 else if (vec.y > top) top = vec.y;
3010 }
3011 }
3012 }
3013 left = left & -64;
3014 right = (right + 63) & -64;
3015 bottom = bottom & -64;
3016 top = (top + 63) & -64;
3017
3018 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3019 vec.x = ft_face->glyph->metrics.horiAdvance;
3020 vec.y = 0;
3021 FT_Vector_Transform(&vec, &transMat);
3022 gm.gmCellIncX = (vec.x+63) >> 6;
3023 gm.gmCellIncY = -((vec.y+63) >> 6);
3024 }
3025 gm.gmBlackBoxX = (right - left) >> 6;
3026 gm.gmBlackBoxY = (top - bottom) >> 6;
3027 gm.gmptGlyphOrigin.x = left >> 6;
3028 gm.gmptGlyphOrigin.y = top >> 6;
3029
3030 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
3031 gm.gmCellIncX, gm.gmCellIncY,
3032 gm.gmBlackBoxX, gm.gmBlackBoxY,
3033 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
3034
3035 IntUnLockFreeType;
3036
3037
3038 if (iFormat == GGO_METRICS)
3039 {
3040 DPRINT("GGO_METRICS Exit!\n");
3041 *pgm = gm;
3042 return 1; /* FIXME */
3043 }
3044
3045 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
3046 {
3047 DPRINT1("Loaded a bitmap\n");
3048 return GDI_ERROR;
3049 }
3050
3051 switch (iFormat)
3052 {
3053 case GGO_BITMAP:
3054 width = gm.gmBlackBoxX;
3055 height = gm.gmBlackBoxY;
3056 pitch = ((width + 31) >> 5) << 2;
3057 needed = pitch * height;
3058
3059 if (!pvBuf || !cjBuf) break;
3060 if (!needed) return GDI_ERROR; /* empty glyph */
3061 if (needed > cjBuf)
3062 return GDI_ERROR;
3063
3064 switch (ft_face->glyph->format)
3065 {
3066 case ft_glyph_format_bitmap:
3067 {
3068 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3069 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
3070 INT h = min( height, ft_face->glyph->bitmap.rows );
3071 while (h--)
3072 {
3073 RtlCopyMemory(dst, src, w);
3074 src += ft_face->glyph->bitmap.pitch;
3075 dst += pitch;
3076 }
3077 break;
3078 }
3079
3080 case ft_glyph_format_outline:
3081 ft_bitmap.width = width;
3082 ft_bitmap.rows = height;
3083 ft_bitmap.pitch = pitch;
3084 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
3085 ft_bitmap.buffer = pvBuf;
3086
3087 IntLockFreeType;
3088 if (needsTransform)
3089 {
3090 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3091 }
3092 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3093 /* Note: FreeType will only set 'black' bits for us. */
3094 RtlZeroMemory(pvBuf, needed);
3095 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3096 IntUnLockFreeType;
3097 break;
3098
3099 default:
3100 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3101 return GDI_ERROR;
3102 }
3103 break;
3104
3105 case GGO_GRAY2_BITMAP:
3106 case GGO_GRAY4_BITMAP:
3107 case GGO_GRAY8_BITMAP:
3108 {
3109 unsigned int mult, row, col;
3110 BYTE *start, *ptr;
3111
3112 width = gm.gmBlackBoxX;
3113 height = gm.gmBlackBoxY;
3114 pitch = (width + 3) / 4 * 4;
3115 needed = pitch * height;
3116
3117 if (!pvBuf || !cjBuf) break;