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