[WIN32SS] Cleanup fonts at process destruction + implement font memory reference...
[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
62 /* The FreeType library is not thread safe, so we have
63 to serialize access to it */
64 static PFAST_MUTEX FreeTypeLock;
65
66 static LIST_ENTRY FontListHead;
67 static PFAST_MUTEX FontListLock;
68 static BOOL RenderingEnabled = TRUE;
69
70 #define IntLockGlobalFonts \
71 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FontListLock)
72
73 #define IntUnLockGlobalFonts \
74 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
75
76 #define ASSERT_GLOBALFONTS_LOCK_HELD() \
77 ASSERT(FreeTypeLock->Owner == KeGetCurrentThread())
78
79 #define IntLockFreeType \
80 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
81
82 #define IntUnLockFreeType \
83 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock)
84
85 #define ASSERT_FREETYPE_LOCK_HELD() \
86 ASSERT(FreeTypeLock->Owner == KeGetCurrentThread())
87
88 #define MAX_FONT_CACHE 256
89
90 static LIST_ENTRY FontCacheListHead;
91 static UINT FontCacheNumEntries;
92
93 static PWCHAR ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */
94 {
95 L"Western", /* 00 */
96 L"Central_European",
97 L"Cyrillic",
98 L"Greek",
99 L"Turkish",
100 L"Hebrew",
101 L"Arabic",
102 L"Baltic",
103 L"Vietnamese", /* 08 */
104 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */
105 L"Thai",
106 L"Japanese",
107 L"CHINESE_GB2312",
108 L"Hangul",
109 L"CHINESE_BIG5",
110 L"Hangul(Johab)",
111 NULL, NULL, /* 23 */
112 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
113 L"Symbol" /* 31 */
114 };
115
116 /*
117 * For TranslateCharsetInfo
118 */
119 #define CP_SYMBOL 42
120 #define MAXTCIINDEX 32
121 static const CHARSETINFO FontTci[MAXTCIINDEX] =
122 {
123 /* ANSI */
124 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
125 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
126 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
127 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
128 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
129 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
130 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
131 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
132 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
133 /* reserved by ANSI */
134 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
135 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
136 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
137 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
138 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
139 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
140 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
141 /* ANSI and OEM */
142 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
143 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
144 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
145 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
146 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
147 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
148 /* Reserved for alternate ANSI and OEM */
149 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
150 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
151 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
152 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
153 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
154 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
155 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
157 /* Reserved for system */
158 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
159 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
160 };
161
162 /* list head */
163 static RTL_STATIC_LIST_HEAD(FontSubstListHead);
164
165 static void
166 SharedMem_AddRef(PSHARED_MEM Ptr)
167 {
168 ASSERT_FREETYPE_LOCK_HELD();
169
170 ++Ptr->RefCount;
171 }
172
173 static PSHARED_FACE
174 SharedFace_Create(FT_Face Face, PSHARED_MEM Memory)
175 {
176 PSHARED_FACE Ptr;
177 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
178 if (Ptr)
179 {
180 Ptr->Face = Face;
181 Ptr->RefCount = 1;
182 Ptr->Memory = Memory;
183 SharedMem_AddRef(Memory);
184 DPRINT("Creating SharedFace for %s\n", Face->family_name);
185 }
186 return Ptr;
187 }
188
189 static PSHARED_MEM
190 SharedMem_Create(PBYTE Buffer, ULONG BufferSize, BOOL IsMapping)
191 {
192 PSHARED_MEM Ptr;
193 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_MEM), TAG_FONT);
194 if (Ptr)
195 {
196 Ptr->Buffer = Buffer;
197 Ptr->BufferSize = BufferSize;
198 Ptr->RefCount = 1;
199 Ptr->IsMapping = IsMapping;
200 DPRINT("Creating SharedMem for %p (%i, %p)\n", Buffer, IsMapping, Ptr);
201 }
202 return Ptr;
203 }
204
205 static void
206 SharedFace_AddRef(PSHARED_FACE Ptr)
207 {
208 ASSERT_FREETYPE_LOCK_HELD();
209
210 ++Ptr->RefCount;
211 }
212
213 static void
214 RemoveCachedEntry(PFONT_CACHE_ENTRY Entry)
215 {
216 ASSERT_FREETYPE_LOCK_HELD();
217
218 FT_Done_Glyph((FT_Glyph)Entry->BitmapGlyph);
219 RemoveEntryList(&Entry->ListEntry);
220 ExFreePoolWithTag(Entry, TAG_FONT);
221 FontCacheNumEntries--;
222 ASSERT(FontCacheNumEntries <= MAX_FONT_CACHE);
223 }
224
225 static void
226 RemoveCacheEntries(FT_Face Face)
227 {
228 PLIST_ENTRY CurrentEntry;
229 PFONT_CACHE_ENTRY FontEntry;
230
231 ASSERT_FREETYPE_LOCK_HELD();
232
233 CurrentEntry = FontCacheListHead.Flink;
234 while (CurrentEntry != &FontCacheListHead)
235 {
236 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
237 CurrentEntry = CurrentEntry->Flink;
238
239 if (FontEntry->Face == Face)
240 {
241 RemoveCachedEntry(FontEntry);
242 }
243 }
244 }
245
246 static void SharedMem_Release(PSHARED_MEM Ptr)
247 {
248 ASSERT_FREETYPE_LOCK_HELD();
249 ASSERT(Ptr->RefCount > 0);
250
251 if (Ptr->RefCount <= 0)
252 return;
253
254 --Ptr->RefCount;
255 if (Ptr->RefCount == 0)
256 {
257 DPRINT("Releasing SharedMem for %p (%i, %p)\n", Ptr->Buffer, Ptr->IsMapping, Ptr);
258 if (Ptr->IsMapping)
259 MmUnmapViewInSystemSpace(Ptr->Buffer);
260 else
261 ExFreePoolWithTag(Ptr->Buffer, TAG_FONT);
262 ExFreePoolWithTag(Ptr, TAG_FONT);
263 }
264 }
265
266 static void
267 SharedFace_Release(PSHARED_FACE Ptr)
268 {
269 IntLockFreeType;
270 ASSERT(Ptr->RefCount > 0);
271
272 if (Ptr->RefCount <= 0)
273 return;
274
275 --Ptr->RefCount;
276 if (Ptr->RefCount == 0)
277 {
278 DPRINT("Releasing SharedFace for %s\n", Ptr->Face->family_name);
279 RemoveCacheEntries(Ptr->Face);
280 FT_Done_Face(Ptr->Face);
281 SharedMem_Release(Ptr->Memory);
282 ExFreePoolWithTag(Ptr, TAG_FONT);
283 }
284 IntUnLockFreeType;
285 }
286
287
288 /*
289 * IntLoadFontSubstList --- loads the list of font substitutes
290 */
291 BOOL FASTCALL
292 IntLoadFontSubstList(PLIST_ENTRY pHead)
293 {
294 NTSTATUS Status;
295 HANDLE KeyHandle;
296 OBJECT_ATTRIBUTES ObjectAttributes;
297 KEY_FULL_INFORMATION KeyFullInfo;
298 ULONG i, Length;
299 UNICODE_STRING FromW, ToW;
300 BYTE InfoBuffer[128];
301 PKEY_VALUE_FULL_INFORMATION pInfo;
302 BYTE CharSets[FONTSUBST_FROM_AND_TO];
303 LPWSTR pch;
304 PFONTSUBST_ENTRY pEntry;
305
306 /* the FontSubstitutes registry key */
307 static UNICODE_STRING FontSubstKey =
308 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\"
309 L"Microsoft\\Windows NT\\CurrentVersion\\"
310 L"FontSubstitutes");
311
312 /* open registry key */
313 InitializeObjectAttributes(&ObjectAttributes, &FontSubstKey,
314 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
315 NULL, NULL);
316 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
317 if (!NT_SUCCESS(Status))
318 {
319 DPRINT("ZwOpenKey failed: 0x%08X\n", Status);
320 return FALSE; /* failure */
321 }
322
323 /* query count of values */
324 Status = ZwQueryKey(KeyHandle, KeyFullInformation,
325 &KeyFullInfo, sizeof(KeyFullInfo), &Length);
326 if (!NT_SUCCESS(Status))
327 {
328 DPRINT("ZwQueryKey failed: 0x%08X\n", Status);
329 ZwClose(KeyHandle);
330 return FALSE; /* failure */
331 }
332
333 /* for each value */
334 for (i = 0; i < KeyFullInfo.Values; ++i)
335 {
336 /* get value name */
337 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
338 InfoBuffer, sizeof(InfoBuffer), &Length);
339 if (!NT_SUCCESS(Status))
340 {
341 DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status);
342 break; /* failure */
343 }
344
345 /* create FromW string */
346 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
347 Length = pInfo->NameLength / sizeof(WCHAR);
348 pInfo->Name[Length] = UNICODE_NULL; /* truncate */
349 Status = RtlCreateUnicodeString(&FromW, pInfo->Name);
350 if (!NT_SUCCESS(Status))
351 {
352 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
353 break; /* failure */
354 }
355
356 /* query value */
357 Status = ZwQueryValueKey(KeyHandle, &FromW, KeyValueFullInformation,
358 InfoBuffer, sizeof(InfoBuffer), &Length);
359 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
360 if (!NT_SUCCESS(Status) || !pInfo->DataLength)
361 {
362 DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status);
363 RtlFreeUnicodeString(&FromW);
364 break; /* failure */
365 }
366
367 /* create ToW string */
368 pch = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
369 Length = pInfo->DataLength / sizeof(WCHAR);
370 pch[Length] = UNICODE_NULL; /* truncate */
371 Status = RtlCreateUnicodeString(&ToW, pch);
372 if (!NT_SUCCESS(Status))
373 {
374 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
375 RtlFreeUnicodeString(&FromW);
376 break; /* failure */
377 }
378
379 /* does charset exist? (from) */
380 CharSets[FONTSUBST_FROM] = DEFAULT_CHARSET;
381 pch = wcsrchr(FromW.Buffer, L',');
382 if (pch)
383 {
384 /* truncate */
385 *pch = UNICODE_NULL;
386 FromW.Length = (pch - FromW.Buffer) * sizeof(WCHAR);
387 /* parse charset number */
388 CharSets[FONTSUBST_FROM] = (BYTE)_wtoi(pch + 1);
389 }
390
391 /* does charset exist? (to) */
392 CharSets[FONTSUBST_TO] = DEFAULT_CHARSET;
393 pch = wcsrchr(ToW.Buffer, L',');
394 if (pch)
395 {
396 /* truncate */
397 *pch = UNICODE_NULL;
398 ToW.Length = (pch - ToW.Buffer) * sizeof(WCHAR);
399 /* parse charset number */
400 CharSets[FONTSUBST_TO] = (BYTE)_wtoi(pch + 1);
401 }
402
403 /* allocate an entry */
404 pEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONTSUBST_ENTRY), TAG_FONT);
405 if (pEntry == NULL)
406 {
407 DPRINT("ExAllocatePoolWithTag failed\n");
408 RtlFreeUnicodeString(&FromW);
409 RtlFreeUnicodeString(&ToW);
410 break; /* failure */
411 }
412
413 /* store to *pEntry */
414 pEntry->FontNames[FONTSUBST_FROM] = FromW;
415 pEntry->FontNames[FONTSUBST_TO] = ToW;
416 pEntry->CharSets[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
417 pEntry->CharSets[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
418
419 /* insert pEntry to *pHead */
420 InsertTailList(pHead, &pEntry->ListEntry);
421 }
422
423 /* close now */
424 ZwClose(KeyHandle);
425
426 return NT_SUCCESS(Status);
427 }
428
429 BOOL FASTCALL
430 InitFontSupport(VOID)
431 {
432 ULONG ulError;
433
434 InitializeListHead(&FontListHead);
435 InitializeListHead(&FontCacheListHead);
436 FontCacheNumEntries = 0;
437 /* Fast Mutexes must be allocated from non paged pool */
438 FontListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
439 if (FontListLock == NULL)
440 {
441 return FALSE;
442 }
443
444 ExInitializeFastMutex(FontListLock);
445 FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
446 if (FreeTypeLock == NULL)
447 {
448 return FALSE;
449 }
450 ExInitializeFastMutex(FreeTypeLock);
451
452 ulError = FT_Init_FreeType(&library);
453 if (ulError)
454 {
455 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
456 return FALSE;
457 }
458
459 IntLoadSystemFonts();
460 IntLoadFontSubstList(&FontSubstListHead);
461
462 return TRUE;
463 }
464
465 VOID
466 FtSetCoordinateTransform(
467 FT_Face face,
468 PMATRIX pmx)
469 {
470 FT_Matrix ftmatrix;
471 FLOATOBJ efTemp;
472
473 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
474 efTemp = pmx->efM11;
475 FLOATOBJ_MulLong(&efTemp, 0x00010000);
476 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
477
478 efTemp = pmx->efM12;
479 FLOATOBJ_MulLong(&efTemp, 0x00010000);
480 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
481
482 efTemp = pmx->efM21;
483 FLOATOBJ_MulLong(&efTemp, 0x00010000);
484 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
485
486 efTemp = pmx->efM22;
487 FLOATOBJ_MulLong(&efTemp, 0x00010000);
488 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
489
490 /* Set the transformation matrix */
491 FT_Set_Transform(face, &ftmatrix, 0);
492 }
493
494 static BOOL
495 SubstituteFontByList(PLIST_ENTRY pHead,
496 PUNICODE_STRING pOutputName,
497 PUNICODE_STRING pInputName,
498 BYTE RequestedCharSet,
499 BYTE CharSetMap[FONTSUBST_FROM_AND_TO])
500 {
501 NTSTATUS Status;
502 PLIST_ENTRY pListEntry;
503 PFONTSUBST_ENTRY pSubstEntry;
504 BYTE CharSets[FONTSUBST_FROM_AND_TO];
505
506 CharSetMap[FONTSUBST_FROM] = DEFAULT_CHARSET;
507 CharSetMap[FONTSUBST_TO] = RequestedCharSet;
508
509 /* for each list entry */
510 for (pListEntry = pHead->Flink;
511 pListEntry != pHead;
512 pListEntry = pListEntry->Flink)
513 {
514 pSubstEntry =
515 (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_ENTRY, ListEntry);
516
517 CharSets[FONTSUBST_FROM] = pSubstEntry->CharSets[FONTSUBST_FROM];
518
519 if (CharSets[FONTSUBST_FROM] != DEFAULT_CHARSET &&
520 CharSets[FONTSUBST_FROM] != RequestedCharSet)
521 {
522 continue; /* not matched */
523 }
524
525 /* does charset number exist? (to) */
526 if (pSubstEntry->CharSets[FONTSUBST_TO] != DEFAULT_CHARSET)
527 {
528 CharSets[FONTSUBST_TO] = pSubstEntry->CharSets[FONTSUBST_TO];
529 }
530 else
531 {
532 CharSets[FONTSUBST_TO] = RequestedCharSet;
533 }
534
535 /* does font name match? */
536 if (!RtlEqualUnicodeString(&pSubstEntry->FontNames[FONTSUBST_FROM],
537 pInputName, TRUE))
538 {
539 continue; /* not matched */
540 }
541
542 /* update *pOutputName */
543 RtlFreeUnicodeString(pOutputName);
544 Status = RtlCreateUnicodeString(pOutputName,
545 pSubstEntry->FontNames[FONTSUBST_TO].Buffer);
546 if (!NT_SUCCESS(Status))
547 {
548 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
549 continue; /* cannot create string */
550 }
551
552 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
553 {
554 /* update CharSetMap */
555 CharSetMap[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
556 CharSetMap[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
557 }
558 return TRUE; /* success */
559 }
560
561 return FALSE;
562 }
563
564 static BOOL
565 SubstituteFontRecurse(PUNICODE_STRING pInOutName, BYTE *pRequestedCharSet)
566 {
567 UINT RecurseCount = 5;
568 UNICODE_STRING OutputNameW = { 0 };
569 BYTE CharSetMap[FONTSUBST_FROM_AND_TO];
570 BOOL Found;
571
572 if (pInOutName->Buffer[0] == UNICODE_NULL)
573 return FALSE;
574
575 while (RecurseCount-- > 0)
576 {
577 RtlInitUnicodeString(&OutputNameW, NULL);
578 Found = SubstituteFontByList(&FontSubstListHead,
579 &OutputNameW, pInOutName,
580 *pRequestedCharSet, CharSetMap);
581 if (!Found)
582 break;
583
584 /* update *pInOutName and *pRequestedCharSet */
585 RtlFreeUnicodeString(pInOutName);
586 *pInOutName = OutputNameW;
587 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
588 CharSetMap[FONTSUBST_FROM] == *pRequestedCharSet)
589 {
590 *pRequestedCharSet = CharSetMap[FONTSUBST_TO];
591 }
592 }
593
594 return TRUE; /* success */
595 }
596
597 /*
598 * IntLoadSystemFonts
599 *
600 * Search the system font directory and adds each font found.
601 */
602 VOID FASTCALL
603 IntLoadSystemFonts(VOID)
604 {
605 OBJECT_ATTRIBUTES ObjectAttributes;
606 UNICODE_STRING Directory, FileName, TempString;
607 IO_STATUS_BLOCK Iosb;
608 HANDLE hDirectory;
609 BYTE *DirInfoBuffer;
610 PFILE_DIRECTORY_INFORMATION DirInfo;
611 BOOLEAN bRestartScan = TRUE;
612 NTSTATUS Status;
613 INT i;
614 static UNICODE_STRING SearchPatterns[] =
615 {
616 RTL_CONSTANT_STRING(L"*.ttf"),
617 RTL_CONSTANT_STRING(L"*.ttc"),
618 RTL_CONSTANT_STRING(L"*.otf"),
619 RTL_CONSTANT_STRING(L"*.otc"),
620 RTL_CONSTANT_STRING(L"*.fon"),
621 RTL_CONSTANT_STRING(L"*.fnt")
622 };
623
624 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
625
626 InitializeObjectAttributes(
627 &ObjectAttributes,
628 &Directory,
629 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
630 NULL,
631 NULL);
632
633 Status = ZwOpenFile(
634 &hDirectory,
635 SYNCHRONIZE | FILE_LIST_DIRECTORY,
636 &ObjectAttributes,
637 &Iosb,
638 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
639 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
640
641 if (NT_SUCCESS(Status))
642 {
643 for (i = 0; i < _countof(SearchPatterns); ++i)
644 {
645 DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
646 if (DirInfoBuffer == NULL)
647 {
648 ZwClose(hDirectory);
649 return;
650 }
651
652 FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
653 if (FileName.Buffer == NULL)
654 {
655 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
656 ZwClose(hDirectory);
657 return;
658 }
659 FileName.Length = 0;
660 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
661
662 while (1)
663 {
664 Status = ZwQueryDirectoryFile(
665 hDirectory,
666 NULL,
667 NULL,
668 NULL,
669 &Iosb,
670 DirInfoBuffer,
671 0x4000,
672 FileDirectoryInformation,
673 FALSE,
674 &SearchPatterns[i],
675 bRestartScan);
676
677 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
678 {
679 break;
680 }
681
682 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
683 while (1)
684 {
685 TempString.Buffer = DirInfo->FileName;
686 TempString.Length =
687 TempString.MaximumLength = DirInfo->FileNameLength;
688 RtlCopyUnicodeString(&FileName, &Directory);
689 RtlAppendUnicodeStringToString(&FileName, &TempString);
690 IntGdiAddFontResource(&FileName, 0);
691 if (DirInfo->NextEntryOffset == 0)
692 break;
693 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
694 }
695
696 bRestartScan = FALSE;
697 }
698
699 ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
700 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
701 }
702 ZwClose(hDirectory);
703 }
704 }
705
706 static BYTE
707 ItalicFromStyle(const char *style_name)
708 {
709 if (style_name == NULL || style_name[0] == 0)
710 return FALSE;
711 if (strstr(style_name, "Italic") != NULL)
712 return TRUE;
713 if (strstr(style_name, "Oblique") != NULL)
714 return TRUE;
715 return FALSE;
716 }
717
718 static LONG
719 WeightFromStyle(const char *style_name)
720 {
721 if (style_name == NULL || style_name[0] == 0)
722 return FW_NORMAL;
723 if (strstr(style_name, "Regular") != NULL)
724 return FW_REGULAR;
725 if (strstr(style_name, "Normal") != NULL)
726 return FW_NORMAL;
727 if (strstr(style_name, "SemiBold") != NULL)
728 return FW_SEMIBOLD;
729 if (strstr(style_name, "UltraBold") != NULL)
730 return FW_ULTRABOLD;
731 if (strstr(style_name, "DemiBold") != NULL)
732 return FW_DEMIBOLD;
733 if (strstr(style_name, "ExtraBold") != NULL)
734 return FW_EXTRABOLD;
735 if (strstr(style_name, "Bold") != NULL)
736 return FW_BOLD;
737 if (strstr(style_name, "UltraLight") != NULL)
738 return FW_ULTRALIGHT;
739 if (strstr(style_name, "ExtraLight") != NULL)
740 return FW_EXTRALIGHT;
741 if (strstr(style_name, "Light") != NULL)
742 return FW_LIGHT;
743 if (strstr(style_name, "Hairline") != NULL)
744 return 50;
745 if (strstr(style_name, "Book") != NULL)
746 return 350;
747 if (strstr(style_name, "ExtraBlack") != NULL)
748 return 950;
749 if (strstr(style_name, "UltraBlack") != NULL)
750 return 1000;
751 if (strstr(style_name, "Black") != NULL)
752 return FW_BLACK;
753 if (strstr(style_name, "Medium") != NULL)
754 return FW_MEDIUM;
755 if (strstr(style_name, "Thin") != NULL)
756 return FW_THIN;
757 if (strstr(style_name, "Heavy") != NULL)
758 return FW_HEAVY;
759 return FW_NORMAL;
760 }
761
762 static INT FASTCALL
763 IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
764 PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
765 {
766 FT_Error Error;
767 PFONT_ENTRY Entry;
768 FONT_ENTRY_MEM* PrivateEntry = NULL;
769 FONTGDI * FontGDI;
770 NTSTATUS Status;
771 FT_Face Face;
772 ANSI_STRING AnsiFaceName;
773 FT_WinFNT_HeaderRec WinFNT;
774 INT FontCount = 0, CharSetCount = 0;
775 PUNICODE_STRING pFileName = pLoadFont->pFileName;
776 DWORD Characteristics = pLoadFont->Characteristics;
777 PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
778 TT_OS2 * pOS2;
779 INT BitIndex;
780 FT_UShort os2_version;
781 FT_ULong os2_ulCodePageRange1;
782 FT_UShort os2_usWeightClass;
783
784 if (SharedFace == NULL && CharSetIndex == -1)
785 {
786 /* load a face from memory */
787 IntLockFreeType;
788 Error = FT_New_Memory_Face(
789 library,
790 pLoadFont->Memory->Buffer,
791 pLoadFont->Memory->BufferSize,
792 ((FontIndex != -1) ? FontIndex : 0),
793 &Face);
794
795 if (!Error)
796 SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
797
798 IntUnLockFreeType;
799
800 if (FT_IS_SFNT(Face))
801 pLoadFont->IsTrueType = TRUE;
802
803 if (Error || SharedFace == NULL)
804 {
805 if (SharedFace)
806 SharedFace_Release(SharedFace);
807
808 if (Error == FT_Err_Unknown_File_Format)
809 DPRINT1("Unknown font file format\n");
810 else
811 DPRINT1("Error reading font (error code: %d)\n", Error);
812 return 0; /* failure */
813 }
814 }
815 else
816 {
817 Face = SharedFace->Face;
818 IntLockFreeType;
819 SharedFace_AddRef(SharedFace);
820 IntUnLockFreeType;
821 }
822
823 /* allocate a FONT_ENTRY */
824 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
825 if (!Entry)
826 {
827 SharedFace_Release(SharedFace);
828 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
829 return 0; /* failure */
830 }
831
832 /* allocate a FONTGDI */
833 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
834 if (!FontGDI)
835 {
836 SharedFace_Release(SharedFace);
837 ExFreePoolWithTag(Entry, TAG_FONT);
838 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
839 return 0; /* failure */
840 }
841
842 /* set file name */
843 if (pFileName)
844 {
845 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool,
846 pFileName->Length + sizeof(UNICODE_NULL),
847 GDITAG_PFF);
848 if (FontGDI->Filename == NULL)
849 {
850 EngFreeMem(FontGDI);
851 SharedFace_Release(SharedFace);
852 ExFreePoolWithTag(Entry, TAG_FONT);
853 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
854 return 0; /* failure */
855 }
856 RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
857 FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
858 }
859 else
860 {
861 FontGDI->Filename = NULL;
862
863 PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT);
864 if (!PrivateEntry)
865 {
866 if (FontGDI->Filename)
867 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
868 EngFreeMem(FontGDI);
869 SharedFace_Release(SharedFace);
870 ExFreePoolWithTag(Entry, TAG_FONT);
871 return 0;
872 }
873
874 PrivateEntry->Entry = Entry;
875 if (pLoadFont->PrivateEntry)
876 {
877 InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry);
878 }
879 else
880 {
881 InitializeListHead(&PrivateEntry->ListEntry);
882 pLoadFont->PrivateEntry = PrivateEntry;
883 }
884 }
885
886 /* set face */
887 FontGDI->SharedFace = SharedFace;
888 FontGDI->CharSet = ANSI_CHARSET;
889 FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name);
890 FontGDI->RequestItalic = FALSE;
891 FontGDI->OriginalWeight = WeightFromStyle(Face->style_name);
892 FontGDI->RequestWeight = FW_NORMAL;
893
894 RtlInitAnsiString(&AnsiFaceName, Face->family_name);
895 Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
896 if (!NT_SUCCESS(Status))
897 {
898 if (PrivateEntry)
899 {
900 if (pLoadFont->PrivateEntry == PrivateEntry)
901 {
902 pLoadFont->PrivateEntry = NULL;
903 }
904 else
905 {
906 RemoveEntryList(&PrivateEntry->ListEntry);
907 }
908 ExFreePoolWithTag(PrivateEntry, TAG_FONT);
909 }
910 if (FontGDI->Filename)
911 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
912 EngFreeMem(FontGDI);
913 SharedFace_Release(SharedFace);
914 ExFreePoolWithTag(Entry, TAG_FONT);
915 return 0;
916 }
917
918 os2_version = 0;
919 IntLockFreeType;
920 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
921 if (pOS2)
922 {
923 os2_version = pOS2->version;
924 os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
925 os2_usWeightClass = pOS2->usWeightClass;
926 }
927 IntUnLockFreeType;
928
929 if (pOS2 && os2_version >= 1)
930 {
931 /* get charset and weight from OS/2 header */
932
933 /* Make sure we do not use this pointer anymore */
934 pOS2 = NULL;
935
936 for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
937 {
938 if (os2_ulCodePageRange1 & (1 << BitIndex))
939 {
940 if (FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
941 continue;
942
943 if ((CharSetIndex == -1 && CharSetCount == 0) ||
944 CharSetIndex == CharSetCount)
945 {
946 FontGDI->CharSet = FontTci[BitIndex].ciCharset;
947 }
948
949 ++CharSetCount;
950 }
951 }
952
953 /* set actual weight */
954 FontGDI->OriginalWeight = os2_usWeightClass;
955 }
956 else
957 {
958 /* get charset from WinFNT header */
959 IntLockFreeType;
960 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
961 if (!Error)
962 {
963 FontGDI->CharSet = WinFNT.charset;
964 }
965 IntUnLockFreeType;
966 }
967
968 /* FIXME: CharSet is invalid on Marlett */
969 if (RtlEqualUnicodeString(&Entry->FaceName, &MarlettW, TRUE))
970 {
971 FontGDI->CharSet = SYMBOL_CHARSET;
972 }
973
974 ++FontCount;
975 DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
976 DPRINT("Num glyphs: %d\n", Face->num_glyphs);
977 DPRINT("CharSet: %d\n", FontGDI->CharSet);
978
979 /* Add this font resource to the font table */
980 Entry->Font = FontGDI;
981 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
982
983 if (Characteristics & FR_PRIVATE)
984 {
985 /* private font */
986 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
987 IntLockProcessPrivateFonts(Win32Process);
988 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
989 IntUnLockProcessPrivateFonts(Win32Process);
990 }
991 else
992 {
993 /* global font */
994 IntLockGlobalFonts;
995 InsertTailList(&FontListHead, &Entry->ListEntry);
996 IntUnLockGlobalFonts;
997 }
998
999 if (FontIndex == -1)
1000 {
1001 if (FT_IS_SFNT(Face))
1002 {
1003 TT_Face TrueType = (TT_Face)Face;
1004 if (TrueType->ttc_header.count > 1)
1005 {
1006 FT_Long i;
1007 for (i = 1; i < TrueType->ttc_header.count; ++i)
1008 {
1009 FontCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
1010 }
1011 }
1012 }
1013 FontIndex = 0;
1014 }
1015
1016 if (CharSetIndex == -1)
1017 {
1018 INT i;
1019
1020 if (pLoadFont->RegValueName.Length == 0)
1021 {
1022 RtlCreateUnicodeString(pValueName, Entry->FaceName.Buffer);
1023 }
1024 else
1025 {
1026 UNICODE_STRING NewString;
1027 USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + Entry->FaceName.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, pValueName);
1036 RtlAppendUnicodeToString(&NewString, L" & ");
1037 RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
1038
1039 RtlFreeUnicodeString(pValueName);
1040 *pValueName = NewString;
1041 }
1042
1043 for (i = 1; i < CharSetCount; ++i)
1044 {
1045 FontCount += IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
1046 }
1047 }
1048
1049 return FontCount; /* number of loaded fonts */
1050 }
1051
1052 /*
1053 * IntGdiAddFontResource
1054 *
1055 * Adds the font resource from the specified file to the system.
1056 */
1057
1058 INT FASTCALL
1059 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
1060 {
1061 NTSTATUS Status;
1062 HANDLE FileHandle;
1063 PVOID Buffer = NULL;
1064 IO_STATUS_BLOCK Iosb;
1065 PVOID SectionObject;
1066 ULONG ViewSize = 0;
1067 LARGE_INTEGER SectionSize;
1068 OBJECT_ATTRIBUTES ObjectAttributes;
1069 GDI_LOAD_FONT LoadFont;
1070 INT FontCount;
1071 HANDLE KeyHandle;
1072 static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
1073
1074 /* Open the font file */
1075 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
1076 Status = ZwOpenFile(
1077 &FileHandle,
1078 FILE_GENERIC_READ | SYNCHRONIZE,
1079 &ObjectAttributes,
1080 &Iosb,
1081 FILE_SHARE_READ,
1082 FILE_SYNCHRONOUS_IO_NONALERT);
1083 if (!NT_SUCCESS(Status))
1084 {
1085 DPRINT("Could not load font file: %wZ\n", FileName);
1086 return 0;
1087 }
1088
1089 SectionSize.QuadPart = 0LL;
1090 Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
1091 NULL, &SectionSize, PAGE_READONLY,
1092 SEC_COMMIT, FileHandle, NULL);
1093 if (!NT_SUCCESS(Status))
1094 {
1095 DPRINT("Could not map file: %wZ\n", FileName);
1096 ZwClose(FileHandle);
1097 return 0;
1098 }
1099 ZwClose(FileHandle);
1100
1101 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
1102 if (!NT_SUCCESS(Status))
1103 {
1104 DPRINT("Could not map file: %wZ\n", FileName);
1105 ObDereferenceObject(SectionObject);
1106 return 0;
1107 }
1108
1109 LoadFont.pFileName = FileName;
1110 LoadFont.Memory = SharedMem_Create(Buffer, ViewSize, TRUE);
1111 LoadFont.Characteristics = Characteristics;
1112 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1113 LoadFont.IsTrueType = FALSE;
1114 LoadFont.PrivateEntry = NULL;
1115 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1116
1117 ObDereferenceObject(SectionObject);
1118
1119 /* Release our copy */
1120 IntLockFreeType;
1121 SharedMem_Release(LoadFont.Memory);
1122 IntUnLockFreeType;
1123
1124 if (FontCount > 0)
1125 {
1126 if (LoadFont.IsTrueType)
1127 {
1128 /* append " (TrueType)" */
1129 UNICODE_STRING NewString;
1130 USHORT Length;
1131
1132 Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length;
1133 NewString.Length = 0;
1134 NewString.MaximumLength = Length + sizeof(WCHAR);
1135 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1136 NewString.MaximumLength,
1137 TAG_USTR);
1138 NewString.Buffer[0] = UNICODE_NULL;
1139
1140 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
1141 RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
1142 RtlFreeUnicodeString(&LoadFont.RegValueName);
1143 LoadFont.RegValueName = NewString;
1144 }
1145
1146 /* registry */
1147 InitializeObjectAttributes(&ObjectAttributes, &FontRegPath,
1148 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1149 NULL, NULL);
1150 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
1151 if (NT_SUCCESS(Status))
1152 {
1153 ULONG DataSize;
1154 LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
1155 if (pFileName)
1156 {
1157 pFileName++;
1158 DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
1159 ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
1160 pFileName, DataSize);
1161 }
1162 ZwClose(KeyHandle);
1163 }
1164 }
1165 RtlFreeUnicodeString(&LoadFont.RegValueName);
1166
1167 return FontCount;
1168 }
1169
1170 HANDLE FASTCALL
1171 IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
1172 {
1173 GDI_LOAD_FONT LoadFont;
1174 FONT_ENTRY_COLL_MEM* EntryCollection;
1175 INT FontCount;
1176 HANDLE Ret = 0;
1177
1178 PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
1179
1180 if (!BufferCopy)
1181 {
1182 *pNumAdded = 0;
1183 return NULL;
1184 }
1185 memcpy(BufferCopy, Buffer, dwSize);
1186
1187 LoadFont.pFileName = NULL;
1188 LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
1189 LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
1190 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1191 LoadFont.IsTrueType = FALSE;
1192 LoadFont.PrivateEntry = NULL;
1193 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1194
1195 RtlFreeUnicodeString(&LoadFont.RegValueName);
1196
1197 /* Release our copy */
1198 IntLockFreeType;
1199 SharedMem_Release(LoadFont.Memory);
1200 IntUnLockFreeType;
1201
1202 if (FontCount > 0)
1203 {
1204 EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
1205 if (EntryCollection)
1206 {
1207 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1208 EntryCollection->Entry = LoadFont.PrivateEntry;
1209 IntLockProcessPrivateFonts(Win32Process);
1210 EntryCollection->Handle = ++Win32Process->PrivateMemFontHandleCount;
1211 InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
1212 IntUnLockProcessPrivateFonts(Win32Process);
1213 Ret = (HANDLE)EntryCollection->Handle;
1214 }
1215 }
1216 *pNumAdded = FontCount;
1217
1218 return Ret;
1219 }
1220
1221 // FIXME: Add RemoveFontResource
1222
1223 static VOID FASTCALL
1224 CleanupFontEntry(PFONT_ENTRY FontEntry)
1225 {
1226 PFONTGDI FontGDI = FontEntry->Font;
1227 PSHARED_FACE SharedFace = FontGDI->SharedFace;
1228
1229 if (FontGDI->Filename)
1230 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1231
1232 EngFreeMem(FontGDI);
1233 SharedFace_Release(SharedFace);
1234 ExFreePoolWithTag(FontEntry, TAG_FONT);
1235 }
1236
1237 VOID FASTCALL
1238 IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
1239 {
1240 PLIST_ENTRY Entry;
1241 PFONT_ENTRY_MEM FontEntry;
1242
1243 while (!IsListEmpty(&Head->ListEntry))
1244 {
1245 Entry = RemoveHeadList(&Head->ListEntry);
1246 FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
1247
1248 CleanupFontEntry(FontEntry->Entry);
1249 ExFreePoolWithTag(FontEntry, TAG_FONT);
1250 }
1251
1252 CleanupFontEntry(Head->Entry);
1253 ExFreePoolWithTag(Head, TAG_FONT);
1254 }
1255
1256 static VOID FASTCALL
1257 UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)
1258 {
1259 PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
1260 PLIST_ENTRY ListEntry;
1261 RemoveEntryList(&Collection->ListEntry);
1262
1263 do {
1264 /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
1265 RemoveEntryList(&FontMemEntry->Entry->ListEntry);
1266
1267 ListEntry = FontMemEntry->ListEntry.Flink;
1268 FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
1269
1270 } while (FontMemEntry != Collection->Entry);
1271 }
1272
1273 BOOL FASTCALL
1274 IntGdiRemoveFontMemResource(HANDLE hMMFont)
1275 {
1276 PLIST_ENTRY Entry;
1277 PFONT_ENTRY_COLL_MEM CurrentEntry;
1278 PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
1279 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1280
1281 IntLockProcessPrivateFonts(Win32Process);
1282 Entry = Win32Process->PrivateMemFontListHead.Flink;
1283 while (Entry != &Win32Process->PrivateMemFontListHead)
1284 {
1285 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1286
1287 if (CurrentEntry->Handle == (UINT)hMMFont)
1288 {
1289 EntryCollection = CurrentEntry;
1290 UnlinkFontMemCollection(CurrentEntry);
1291 break;
1292 }
1293
1294 Entry = Entry->Flink;
1295 }
1296 IntUnLockProcessPrivateFonts(Win32Process);
1297
1298 if (EntryCollection)
1299 {
1300 IntGdiCleanupMemEntry(EntryCollection->Entry);
1301 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1302 return TRUE;
1303 }
1304 return FALSE;
1305 }
1306
1307
1308 VOID FASTCALL
1309 IntGdiCleanupPrivateFontsForProcess(VOID)
1310 {
1311 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1312 PLIST_ENTRY Entry;
1313 PFONT_ENTRY_COLL_MEM EntryCollection;
1314
1315 DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
1316 do {
1317 Entry = NULL;
1318 EntryCollection = NULL;
1319
1320 IntLockProcessPrivateFonts(Win32Process);
1321 if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
1322 {
1323 Entry = Win32Process->PrivateMemFontListHead.Flink;
1324 EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1325 UnlinkFontMemCollection(EntryCollection);
1326 }
1327 IntUnLockProcessPrivateFonts(Win32Process);
1328
1329 if (EntryCollection)
1330 {
1331 IntGdiCleanupMemEntry(EntryCollection->Entry);
1332 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1333 }
1334 else
1335 {
1336 /* No Mem fonts anymore, see if we have any other private fonts left */
1337 Entry = NULL;
1338 IntLockProcessPrivateFonts(Win32Process);
1339 if (!IsListEmpty(&Win32Process->PrivateFontListHead))
1340 {
1341 Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
1342 }
1343 IntUnLockProcessPrivateFonts(Win32Process);
1344
1345 if (Entry)
1346 {
1347 CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
1348 }
1349 }
1350
1351 } while (Entry);
1352 }
1353
1354 BOOL FASTCALL
1355 IntIsFontRenderingEnabled(VOID)
1356 {
1357 BOOL Ret = RenderingEnabled;
1358 HDC hDC;
1359
1360 hDC = IntGetScreenDC();
1361 if (hDC)
1362 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
1363
1364 return Ret;
1365 }
1366
1367 VOID FASTCALL
1368 IntEnableFontRendering(BOOL Enable)
1369 {
1370 RenderingEnabled = Enable;
1371 }
1372
1373 FT_Render_Mode FASTCALL
1374 IntGetFontRenderMode(LOGFONTW *logfont)
1375 {
1376 switch (logfont->lfQuality)
1377 {
1378 case ANTIALIASED_QUALITY:
1379 case NONANTIALIASED_QUALITY:
1380 return FT_RENDER_MODE_MONO;
1381 case DRAFT_QUALITY:
1382 return FT_RENDER_MODE_LIGHT;
1383 /* case CLEARTYPE_QUALITY:
1384 return FT_RENDER_MODE_LCD; */
1385 }
1386 return FT_RENDER_MODE_NORMAL;
1387 }
1388
1389
1390 NTSTATUS FASTCALL
1391 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
1392 {
1393 PLFONT plfont;
1394 LOGFONTW *plf;
1395
1396 plfont = LFONT_AllocFontWithHandle();
1397 if (!plfont)
1398 {
1399 return STATUS_NO_MEMORY;
1400 }
1401
1402 ExInitializePushLock(&plfont->lock);
1403 *NewFont = plfont->BaseObject.hHmgr;
1404 plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
1405 RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
1406 if (lf->lfEscapement != lf->lfOrientation)
1407 {
1408 /* This should really depend on whether GM_ADVANCED is set */
1409 plf->lfOrientation = plf->lfEscapement;
1410 }
1411 LFONT_UnlockFont(plfont);
1412
1413 return STATUS_SUCCESS;
1414 }
1415
1416 /*************************************************************************
1417 * TranslateCharsetInfo
1418 *
1419 * Fills a CHARSETINFO structure for a character set, code page, or
1420 * font. This allows making the correspondance between different labelings
1421 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
1422 * of the same encoding.
1423 *
1424 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
1425 * only one codepage should be set in *Src.
1426 *
1427 * RETURNS
1428 * TRUE on success, FALSE on failure.
1429 *
1430 */
1431 static BOOLEAN APIENTRY
1432 IntTranslateCharsetInfo(PDWORD Src, /* [in]
1433 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
1434 if flags == TCI_SRCCHARSET: a character set value
1435 if flags == TCI_SRCCODEPAGE: a code page value */
1436 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
1437 DWORD Flags /* [in] determines interpretation of lpSrc */)
1438 {
1439 int Index = 0;
1440
1441 switch (Flags)
1442 {
1443 case TCI_SRCFONTSIG:
1444 while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
1445 {
1446 Index++;
1447 }
1448 break;
1449 case TCI_SRCCODEPAGE:
1450 while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciACP)
1451 {
1452 Index++;
1453 }
1454 break;
1455 case TCI_SRCCHARSET:
1456 while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciCharset)
1457 {
1458 Index++;
1459 }
1460 break;
1461 default:
1462 return FALSE;
1463 }
1464
1465 if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == FontTci[Index].ciCharset)
1466 {
1467 return FALSE;
1468 }
1469
1470 RtlCopyMemory(Cs, &FontTci[Index], sizeof(CHARSETINFO));
1471
1472 return TRUE;
1473 }
1474
1475
1476 static BOOL face_has_symbol_charmap(FT_Face ft_face)
1477 {
1478 int i;
1479
1480 for(i = 0; i < ft_face->num_charmaps; i++)
1481 {
1482 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
1483 return TRUE;
1484 }
1485 return FALSE;
1486 }
1487
1488
1489 static void FASTCALL
1490 FillTMEx(TEXTMETRICW *TM, PFONTGDI FontGDI,
1491 TT_OS2 *pOS2, TT_HoriHeader *pHori,
1492 FT_WinFNT_HeaderRec *pFNT, BOOL RealFont)
1493 {
1494 FT_Fixed XScale, YScale;
1495 int Ascent, Descent;
1496 FT_Face Face = FontGDI->SharedFace->Face;
1497
1498 XScale = Face->size->metrics.x_scale;
1499 YScale = Face->size->metrics.y_scale;
1500
1501 if (pFNT)
1502 {
1503 TM->tmHeight = pFNT->pixel_height;
1504 TM->tmAscent = pFNT->ascent;
1505 TM->tmDescent = TM->tmHeight - TM->tmAscent;
1506 TM->tmInternalLeading = pFNT->internal_leading;
1507 TM->tmExternalLeading = pFNT->external_leading;
1508 TM->tmAveCharWidth = pFNT->avg_width;
1509 TM->tmMaxCharWidth = pFNT->max_width;
1510 TM->tmOverhang = 0;
1511 TM->tmDigitizedAspectX = pFNT->horizontal_resolution;
1512 TM->tmDigitizedAspectY = pFNT->vertical_resolution;
1513 TM->tmFirstChar = pFNT->first_char;
1514 TM->tmLastChar = pFNT->last_char;
1515 TM->tmDefaultChar = pFNT->default_char + pFNT->first_char;
1516 TM->tmBreakChar = pFNT->break_char + pFNT->first_char;
1517 TM->tmPitchAndFamily = pFNT->pitch_and_family;
1518 if (RealFont)
1519 {
1520 TM->tmWeight = FontGDI->OriginalWeight;
1521 TM->tmItalic = FontGDI->OriginalItalic;
1522 TM->tmUnderlined = pFNT->underline;
1523 TM->tmStruckOut = pFNT->strike_out;
1524 TM->tmCharSet = pFNT->charset;
1525 }
1526 else
1527 {
1528 TM->tmWeight = FontGDI->RequestWeight;
1529 TM->tmItalic = FontGDI->RequestItalic;
1530 TM->tmUnderlined = FontGDI->RequestUnderline;
1531 TM->tmStruckOut = FontGDI->RequestStrikeOut;
1532 TM->tmCharSet = FontGDI->CharSet;
1533 }
1534 return;
1535 }
1536
1537 if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
1538 {
1539 Ascent = pHori->Ascender;
1540 Descent = -pHori->Descender;
1541 }
1542 else
1543 {
1544 Ascent = pOS2->usWinAscent;
1545 Descent = pOS2->usWinDescent;
1546 }
1547
1548 #if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */
1549 TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
1550 TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
1551 #else /* This (ros) code was previously affected by a FreeType bug, but it works now */
1552 TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* Units above baseline */
1553 TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* Units below baseline */
1554 #endif
1555 TM->tmInternalLeading = (FT_MulFix(Ascent + Descent - Face->units_per_EM, YScale) + 32) >> 6;
1556
1557 TM->tmHeight = TM->tmAscent + TM->tmDescent;
1558
1559 /* MSDN says:
1560 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1561 */
1562 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
1563 - ((Ascent + Descent)
1564 - (pHori->Ascender - pHori->Descender)),
1565 YScale) + 32) >> 6);
1566
1567 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
1568 if (TM->tmAveCharWidth == 0)
1569 {
1570 TM->tmAveCharWidth = 1;
1571 }
1572
1573 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
1574 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
1575
1576 if (RealFont)
1577 {
1578 TM->tmWeight = FontGDI->OriginalWeight;
1579 }
1580 else
1581 {
1582 if (FontGDI->OriginalWeight != FW_DONTCARE &&
1583 FontGDI->OriginalWeight != FW_NORMAL)
1584 {
1585 TM->tmWeight = FontGDI->OriginalWeight;
1586 }
1587 else
1588 {
1589 TM->tmWeight = FontGDI->RequestWeight;
1590 }
1591 }
1592
1593 TM->tmOverhang = 0;
1594 TM->tmDigitizedAspectX = 96;
1595 TM->tmDigitizedAspectY = 96;
1596 if (face_has_symbol_charmap(Face) ||
1597 (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
1598 {
1599 USHORT cpOEM, cpAnsi;
1600
1601 EngGetCurrentCodePage(&cpOEM, &cpAnsi);
1602 TM->tmFirstChar = 0;
1603 switch(cpAnsi)
1604 {
1605 case 1257: /* Baltic */
1606 TM->tmLastChar = 0xf8fd;
1607 break;
1608 default:
1609 TM->tmLastChar = 0xf0ff;
1610 }
1611 TM->tmBreakChar = 0x20;
1612 TM->tmDefaultChar = 0x1f;
1613 }
1614 else
1615 {
1616 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
1617 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
1618
1619 if(pOS2->usFirstCharIndex <= 1)
1620 TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
1621 else if (pOS2->usFirstCharIndex > 0xff)
1622 TM->tmBreakChar = 0x20;
1623 else
1624 TM->tmBreakChar = pOS2->usFirstCharIndex;
1625 TM->tmDefaultChar = TM->tmBreakChar - 1;
1626 }
1627
1628 if (RealFont)
1629 {
1630 TM->tmItalic = FontGDI->OriginalItalic;
1631 TM->tmUnderlined = FALSE;
1632 TM->tmStruckOut = FALSE;
1633 }
1634 else
1635 {
1636 if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
1637 {
1638 TM->tmItalic = 0xFF;
1639 }
1640 else
1641 {
1642 TM->tmItalic = 0;
1643 }
1644 TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
1645 TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
1646 }
1647
1648 if (!FT_IS_FIXED_WIDTH(Face))
1649 {
1650 switch (pOS2->panose[PAN_PROPORTION_INDEX])
1651 {
1652 case PAN_PROP_MONOSPACED:
1653 TM->tmPitchAndFamily = 0;
1654 break;
1655 default:
1656 TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH;
1657 break;
1658 }
1659 }
1660 else
1661 {
1662 TM->tmPitchAndFamily = 0;
1663 }
1664
1665 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
1666 {
1667 case PAN_FAMILY_SCRIPT:
1668 TM->tmPitchAndFamily |= FF_SCRIPT;
1669 break;
1670 case PAN_FAMILY_DECORATIVE:
1671 TM->tmPitchAndFamily |= FF_DECORATIVE;
1672 break;
1673
1674 case PAN_ANY:
1675 case PAN_NO_FIT:
1676 case PAN_FAMILY_TEXT_DISPLAY:
1677 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
1678 /* Which is clearly not what the panose spec says. */
1679 if (TM->tmPitchAndFamily == 0) /* Fixed */
1680 {
1681 TM->tmPitchAndFamily = FF_MODERN;
1682 }
1683 else
1684 {
1685 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
1686 {
1687 case PAN_ANY:
1688 case PAN_NO_FIT:
1689 default:
1690 TM->tmPitchAndFamily |= FF_DONTCARE;
1691 break;
1692
1693 case PAN_SERIF_COVE:
1694 case PAN_SERIF_OBTUSE_COVE:
1695 case PAN_SERIF_SQUARE_COVE:
1696 case PAN_SERIF_OBTUSE_SQUARE_COVE:
1697 case PAN_SERIF_SQUARE:
1698 case PAN_SERIF_THIN:
1699 case PAN_SERIF_BONE:
1700 case PAN_SERIF_EXAGGERATED:
1701 case PAN_SERIF_TRIANGLE:
1702 TM->tmPitchAndFamily |= FF_ROMAN;
1703 break;
1704
1705 case PAN_SERIF_NORMAL_SANS:
1706 case PAN_SERIF_OBTUSE_SANS:
1707 case PAN_SERIF_PERP_SANS:
1708 case PAN_SERIF_FLARED:
1709 case PAN_SERIF_ROUNDED:
1710 TM->tmPitchAndFamily |= FF_SWISS;
1711 break;
1712 }
1713 }
1714 break;
1715 default:
1716 TM->tmPitchAndFamily |= FF_DONTCARE;
1717 }
1718
1719 if (FT_IS_SCALABLE(Face))
1720 {
1721 TM->tmPitchAndFamily |= TMPF_VECTOR;
1722 }
1723 if (FT_IS_SFNT(Face))
1724 {
1725 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
1726 }
1727
1728 TM->tmCharSet = FontGDI->CharSet;
1729 }
1730
1731 static void FASTCALL
1732 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
1733 TT_OS2 *pOS2, TT_HoriHeader *pHori,
1734 FT_WinFNT_HeaderRec *pFNT)
1735 {
1736 FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
1737 }
1738
1739 /*************************************************************
1740 * IntGetOutlineTextMetrics
1741 *
1742 */
1743 INT FASTCALL
1744 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
1745 UINT Size,
1746 OUTLINETEXTMETRICW *Otm)
1747 {
1748 unsigned Needed;
1749 TT_OS2 *pOS2;
1750 TT_HoriHeader *pHori;
1751 TT_Postscript *pPost;
1752 FT_Fixed XScale, YScale;
1753 ANSI_STRING FamilyNameA, StyleNameA;
1754 UNICODE_STRING FamilyNameW, StyleNameW, Regular;
1755 FT_WinFNT_HeaderRec Win;
1756 FT_Error Error;
1757 char *Cp;
1758 NTSTATUS status;
1759 FT_Face Face = FontGDI->SharedFace->Face;
1760
1761 Needed = sizeof(OUTLINETEXTMETRICW);
1762
1763 RtlInitAnsiString(&FamilyNameA, Face->family_name);
1764 status = RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
1765 if (!NT_SUCCESS(status))
1766 {
1767 return 0;
1768 }
1769
1770 RtlInitAnsiString(&StyleNameA, Face->style_name);
1771 status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
1772 if (!NT_SUCCESS(status))
1773 {
1774 RtlFreeUnicodeString(&FamilyNameW);
1775 return 0;
1776 }
1777
1778 /* These names should be read from the TT name table */
1779
1780 /* Length of otmpFamilyName */
1781 Needed += FamilyNameW.Length + sizeof(WCHAR);
1782
1783 RtlInitUnicodeString(&Regular, L"Regular");
1784 /* Length of otmpFaceName */
1785 if (RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
1786 {
1787 Needed += FamilyNameW.Length + sizeof(WCHAR); /* Just the family name */
1788 }
1789 else
1790 {
1791 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
1792 }
1793
1794 /* Length of otmpStyleName */
1795 Needed += StyleNameW.Length + sizeof(WCHAR);
1796
1797 /* Length of otmpFullName */
1798 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
1799
1800 if (Size < Needed)
1801 {
1802 RtlFreeUnicodeString(&FamilyNameW);
1803 RtlFreeUnicodeString(&StyleNameW);
1804 return Needed;
1805 }
1806
1807 XScale = Face->size->metrics.x_scale;
1808 YScale = Face->size->metrics.y_scale;
1809
1810 IntLockFreeType;
1811 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
1812 if (NULL == pOS2)
1813 {
1814 IntUnLockFreeType;
1815 DPRINT1("Can't find OS/2 table - not TT font?\n");
1816 RtlFreeUnicodeString(&StyleNameW);
1817 RtlFreeUnicodeString(&FamilyNameW);
1818 return 0;
1819 }
1820
1821 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
1822 if (NULL == pHori)
1823 {
1824 IntUnLockFreeType;
1825 DPRINT1("Can't find HHEA table - not TT font?\n");
1826 RtlFreeUnicodeString(&StyleNameW);
1827 RtlFreeUnicodeString(&FamilyNameW);
1828 return 0;
1829 }
1830
1831 pPost = FT_Get_Sfnt_Table(Face, ft_sfnt_post); /* We can live with this failing */
1832
1833 Error = FT_Get_WinFNT_Header(Face , &Win);
1834
1835 Otm->otmSize = Needed;
1836
1837 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
1838
1839 Otm->otmFiller = 0;
1840 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1841 Otm->otmfsSelection = pOS2->fsSelection;
1842 Otm->otmfsType = pOS2->fsType;
1843 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1844 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1845 Otm->otmItalicAngle = 0; /* POST table */
1846 Otm->otmEMSquare = Face->units_per_EM;
1847 Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
1848 Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
1849 Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
1850 Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
1851 Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
1852 Otm->otmrcFontBox.left = (FT_MulFix(Face->bbox.xMin, XScale) + 32) >> 6;
1853 Otm->otmrcFontBox.right = (FT_MulFix(Face->bbox.xMax, XScale) + 32) >> 6;
1854 Otm->otmrcFontBox.top = (FT_MulFix(Face->bbox.yMax, YScale) + 32) >> 6;
1855 Otm->otmrcFontBox.bottom = (FT_MulFix(Face->bbox.yMin, YScale) + 32) >> 6;
1856 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
1857 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
1858 Otm->otmMacLineGap = Otm->otmLineGap;
1859 Otm->otmusMinimumPPEM = 0; /* TT Header */
1860 Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
1861 Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
1862 Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
1863 Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
1864 Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
1865 Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
1866 Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
1867 Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
1868 Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
1869 Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
1870 if (!pPost)
1871 {
1872 Otm->otmsUnderscoreSize = 0;
1873 Otm->otmsUnderscorePosition = 0;
1874 }
1875 else
1876 {
1877 Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
1878 Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
1879 }
1880
1881 IntUnLockFreeType;
1882
1883 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1884 Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
1885 Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
1886 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1887 Cp += FamilyNameW.Length + sizeof(WCHAR);
1888 Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
1889 wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
1890 Cp += StyleNameW.Length + sizeof(WCHAR);
1891 Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
1892 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1893 if (!RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
1894 {
1895 wcscat((WCHAR*) Cp, L" ");
1896 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
1897 Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
1898 }
1899 else
1900 {
1901 Cp += FamilyNameW.Length + sizeof(WCHAR);
1902 }
1903 Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
1904 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1905 wcscat((WCHAR*) Cp, L" ");
1906 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
1907
1908 RtlFreeUnicodeString(&StyleNameW);
1909 RtlFreeUnicodeString(&FamilyNameW);
1910
1911 return Needed;
1912 }
1913
1914 static PFONTGDI FASTCALL
1915 FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
1916 {
1917 PLIST_ENTRY Entry;
1918 PFONT_ENTRY CurrentEntry;
1919 ANSI_STRING EntryFaceNameA;
1920 UNICODE_STRING EntryFaceNameW;
1921 FONTGDI *FontGDI;
1922 NTSTATUS status;
1923
1924 Entry = Head->Flink;
1925 while (Entry != Head)
1926 {
1927 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1928
1929 FontGDI = CurrentEntry->Font;
1930 ASSERT(FontGDI);
1931
1932 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
1933 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
1934 if (!NT_SUCCESS(status))
1935 {
1936 break;
1937 }
1938
1939 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
1940 {
1941 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
1942 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
1943 }
1944
1945 if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE))
1946 {
1947 RtlFreeUnicodeString(&EntryFaceNameW);
1948 return FontGDI;
1949 }
1950
1951 RtlFreeUnicodeString(&EntryFaceNameW);
1952 Entry = Entry->Flink;
1953 }
1954
1955 return NULL;
1956 }
1957
1958 static PFONTGDI FASTCALL
1959 FindFaceNameInLists(PUNICODE_STRING FaceName)
1960 {
1961 PPROCESSINFO Win32Process;
1962 PFONTGDI Font;
1963
1964 /* Search the process local list.
1965 We do not have to search the 'Mem' list, since those fonts are linked in the PrivateFontListHead */
1966 Win32Process = PsGetCurrentProcessWin32Process();
1967 IntLockProcessPrivateFonts(Win32Process);
1968 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
1969 IntUnLockProcessPrivateFonts(Win32Process);
1970 if (NULL != Font)
1971 {
1972 return Font;
1973 }
1974
1975 /* Search the global list */
1976 IntLockGlobalFonts;
1977 Font = FindFaceNameInList(FaceName, &FontListHead);
1978 IntUnLockGlobalFonts;
1979
1980 return Font;
1981 }
1982
1983 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
1984 static BYTE
1985 CharSetFromLangID(LANGID LangID)
1986 {
1987 /* FIXME: Add more and fix if wrong */
1988 switch (PRIMARYLANGID(LangID))
1989 {
1990 case LANG_CHINESE:
1991 switch (SUBLANGID(LangID))
1992 {
1993 case SUBLANG_CHINESE_TRADITIONAL:
1994 return CHINESEBIG5_CHARSET;
1995 case SUBLANG_CHINESE_SIMPLIFIED:
1996 default:
1997 break;
1998 }
1999 return GB2312_CHARSET;
2000
2001 case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
2002 case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
2003 return EASTEUROPE_CHARSET;
2004
2005 case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
2006 case LANG_SERBIAN: case LANG_UKRAINIAN:
2007 return RUSSIAN_CHARSET;
2008
2009 case LANG_ARABIC: return ARABIC_CHARSET;
2010 case LANG_GREEK: return GREEK_CHARSET;
2011 case LANG_HEBREW: return HEBREW_CHARSET;
2012 case LANG_JAPANESE: return SHIFTJIS_CHARSET;
2013 case LANG_KOREAN: return JOHAB_CHARSET;
2014 case LANG_TURKISH: return TURKISH_CHARSET;
2015 case LANG_THAI: return THAI_CHARSET;
2016 case LANG_LATVIAN: return BALTIC_CHARSET;
2017 case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
2018
2019 case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
2020 case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
2021 case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
2022 case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
2023 case LANG_SWEDISH: default:
2024 return ANSI_CHARSET;
2025 }
2026 }
2027
2028 static void
2029 SwapEndian(LPVOID pvData, DWORD Size)
2030 {
2031 BYTE b, *pb = pvData;
2032 Size /= 2;
2033 while (Size-- > 0)
2034 {
2035 b = pb[0];
2036 pb[0] = pb[1];
2037 pb[1] = b;
2038 ++pb; ++pb;
2039 }
2040 }
2041
2042 static NTSTATUS
2043 IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face)
2044 {
2045 FT_SfntName Name;
2046 INT i, Count;
2047 WCHAR Buf[LF_FACESIZE];
2048 NTSTATUS Status = STATUS_NOT_FOUND;
2049
2050 RtlInitUnicodeString(pLocalNameW, NULL);
2051
2052 Count = FT_Get_Sfnt_Name_Count(Face);
2053 for (i = 0; i < Count; ++i)
2054 {
2055 FT_Get_Sfnt_Name(Face, i, &Name);
2056 if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
2057 Name.encoding_id != TT_MS_ID_UNICODE_CS)
2058 {
2059 continue; /* not Microsoft Unicode name */
2060 }
2061
2062 if (Name.name_id != TT_NAME_ID_FONT_FAMILY ||
2063 Name.string == NULL || Name.string_len == 0 ||
2064 (Name.string[0] == 0 && Name.string[1] == 0))
2065 {
2066 continue; /* not family name */
2067 }
2068
2069 if (sizeof(Buf) < Name.string_len + sizeof(UNICODE_NULL))
2070 {
2071 continue; /* name too long */
2072 }
2073
2074 /* NOTE: Name.string is not null-terminated */
2075 RtlCopyMemory(Buf, Name.string, Name.string_len);
2076 Buf[Name.string_len / sizeof(WCHAR)] = UNICODE_NULL;
2077
2078 /* Convert UTF-16 big endian to little endian */
2079 SwapEndian(Buf, Name.string_len);
2080 #if 0
2081 DPRINT("IntGetFontLocalizedName: %S (%d)\n", Buf, Name.string_len);
2082 #endif
2083
2084 Status = RtlCreateUnicodeString(pLocalNameW, Buf);
2085 break;
2086 }
2087
2088 return Status;
2089 }
2090
2091 static void FASTCALL
2092 FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
2093 {
2094 ANSI_STRING StyleA;
2095 UNICODE_STRING StyleW;
2096 TT_OS2 *pOS2;
2097 FONTSIGNATURE fs;
2098 CHARSETINFO CharSetInfo;
2099 unsigned i, Size;
2100 OUTLINETEXTMETRICW *Otm;
2101 LOGFONTW *Lf;
2102 TEXTMETRICW *TM;
2103 NEWTEXTMETRICW *Ntm;
2104 DWORD fs0;
2105 NTSTATUS status;
2106 FT_Face Face = FontGDI->SharedFace->Face;
2107
2108 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
2109 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2110 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2111 if (!Otm)
2112 {
2113 return;
2114 }
2115 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2116
2117 Lf = &Info->EnumLogFontEx.elfLogFont;
2118 TM = &Otm->otmTextMetrics;
2119
2120 Lf->lfHeight = TM->tmHeight;
2121 Lf->lfWidth = TM->tmAveCharWidth;
2122 Lf->lfWeight = TM->tmWeight;
2123 Lf->lfItalic = TM->tmItalic;
2124 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
2125 Lf->lfCharSet = TM->tmCharSet;
2126 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
2127 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
2128 Lf->lfQuality = PROOF_QUALITY;
2129
2130 Ntm = &Info->NewTextMetricEx.ntmTm;
2131 Ntm->tmHeight = TM->tmHeight;
2132 Ntm->tmAscent = TM->tmAscent;
2133 Ntm->tmDescent = TM->tmDescent;
2134 Ntm->tmInternalLeading = TM->tmInternalLeading;
2135 Ntm->tmExternalLeading = TM->tmExternalLeading;
2136 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
2137 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
2138 Ntm->tmWeight = TM->tmWeight;
2139 Ntm->tmOverhang = TM->tmOverhang;
2140 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
2141 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
2142 Ntm->tmFirstChar = TM->tmFirstChar;
2143 Ntm->tmLastChar = TM->tmLastChar;
2144 Ntm->tmDefaultChar = TM->tmDefaultChar;
2145 Ntm->tmBreakChar = TM->tmBreakChar;
2146 Ntm->tmItalic = TM->tmItalic;
2147 Ntm->tmUnderlined = TM->tmUnderlined;
2148 Ntm->tmStruckOut = TM->tmStruckOut;
2149 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
2150 Ntm->tmCharSet = TM->tmCharSet;
2151 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
2152
2153 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
2154
2155 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
2156
2157 Ntm->ntmSizeEM = Otm->otmEMSquare;
2158 Ntm->ntmCellHeight = Otm->otmEMSquare;
2159 Ntm->ntmAvgWidth = 0;
2160
2161 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
2162 ? TRUETYPE_FONTTYPE : 0);
2163
2164 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
2165 Info->FontType |= RASTER_FONTTYPE;
2166
2167 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2168
2169 /* try the localized name */
2170 status = STATUS_UNSUCCESSFUL;
2171 if (CharSetFromLangID(gusLanguageID) == FontGDI->CharSet)
2172 {
2173 /* get localized name */
2174 UNICODE_STRING LocalNameW;
2175 status = IntGetFontLocalizedName(&LocalNameW, Face);
2176 if (NT_SUCCESS(status))
2177 {
2178 /* store it */
2179 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
2180 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
2181 LocalNameW.Buffer);
2182 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2183 sizeof(Info->EnumLogFontEx.elfFullName),
2184 LocalNameW.Buffer);
2185 }
2186 RtlFreeUnicodeString(&LocalNameW);
2187 }
2188
2189 /* if localized name was unavailable */
2190 if (!NT_SUCCESS(status))
2191 {
2192 /* store English name */
2193 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
2194 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
2195 FaceName);
2196 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2197 sizeof(Info->EnumLogFontEx.elfFullName),
2198 FaceName);
2199 }
2200
2201 RtlInitAnsiString(&StyleA, Face->style_name);
2202 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
2203 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
2204 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
2205 if (!NT_SUCCESS(status))
2206 {
2207 return;
2208 }
2209 if (StyleW.Length)
2210 {
2211 if (wcslen(Info->EnumLogFontEx.elfFullName) +
2212 StyleW.Length / sizeof(WCHAR) + 1 <=
2213 sizeof(Info->EnumLogFontEx.elfFullName))
2214 {
2215 wcscat(Info->EnumLogFontEx.elfFullName, L" ");
2216 wcscat(Info->EnumLogFontEx.elfFullName, StyleW.Buffer);
2217 }
2218 }
2219
2220 Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
2221 Info->EnumLogFontEx.elfScript[0] = L'\0';
2222 IntLockFreeType;
2223 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2224
2225 if (!pOS2)
2226 {
2227 IntUnLockFreeType;
2228 return;
2229 }
2230
2231 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2232 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2233 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2234 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2235 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2236 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2237
2238 if (0 == pOS2->version)
2239 {
2240 FT_UInt Dummy;
2241
2242 if (FT_Get_First_Char(Face, &Dummy) < 0x100)
2243 fs.fsCsb[0] |= FS_LATIN1;
2244 else
2245 fs.fsCsb[0] |= FS_SYMBOL;
2246 }
2247 IntUnLockFreeType;
2248
2249 if (fs.fsCsb[0] == 0)
2250 {
2251 /* Let's see if we can find any interesting cmaps */
2252 for (i = 0; i < (UINT)Face->num_charmaps; i++)
2253 {
2254 switch (Face->charmaps[i]->encoding)
2255 {
2256 case FT_ENCODING_UNICODE:
2257 case FT_ENCODING_APPLE_ROMAN:
2258 fs.fsCsb[0] |= FS_LATIN1;
2259 break;
2260 case FT_ENCODING_MS_SYMBOL:
2261 fs.fsCsb[0] |= FS_SYMBOL;
2262 break;
2263 default:
2264 break;
2265 }
2266 }
2267 }
2268
2269 for (i = 0; i < MAXTCIINDEX; i++)
2270 {
2271 fs0 = 1L << i;
2272 if (fs.fsCsb[0] & fs0)
2273 {
2274 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
2275 {
2276 CharSetInfo.ciCharset = DEFAULT_CHARSET;
2277 }
2278 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
2279 {
2280 Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
2281 if (ElfScripts[i])
2282 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
2283 else
2284 {
2285 DPRINT1("Unknown elfscript for bit %u\n", i);
2286 }
2287 }
2288 }
2289 }
2290 Info->NewTextMetricEx.ntmFontSig = fs;
2291 }
2292
2293 static int FASTCALL
2294 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
2295 {
2296 DWORD i;
2297 UNICODE_STRING InfoFaceName;
2298
2299 for (i = 0; i < InfoEntries; i++)
2300 {
2301 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
2302 if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE))
2303 {
2304 return i;
2305 }
2306 }
2307
2308 return -1;
2309 }
2310
2311 static BOOLEAN FASTCALL
2312 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
2313 PFONTFAMILYINFO Info, DWORD InfoEntries)
2314 {
2315 UNICODE_STRING LogFontFaceName;
2316
2317 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
2318 if (0 != LogFontFaceName.Length &&
2319 !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE))
2320 {
2321 return FALSE;
2322 }
2323
2324 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
2325 }
2326
2327 static BOOLEAN FASTCALL
2328 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
2329 PFONTFAMILYINFO Info,
2330 DWORD *Count,
2331 DWORD Size,
2332 PLIST_ENTRY Head)
2333 {
2334 PLIST_ENTRY Entry;
2335 PFONT_ENTRY CurrentEntry;
2336 ANSI_STRING EntryFaceNameA;
2337 UNICODE_STRING EntryFaceNameW;
2338 FONTGDI *FontGDI;
2339 NTSTATUS status;
2340
2341 Entry = Head->Flink;
2342 while (Entry != Head)
2343 {
2344 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2345
2346 FontGDI = CurrentEntry->Font;
2347 ASSERT(FontGDI);
2348
2349 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
2350 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2351 if (!NT_SUCCESS(status))
2352 {
2353 return FALSE;
2354 }
2355
2356 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2357 {
2358 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2359 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2360 }
2361
2362 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
2363 {
2364 if (*Count < Size)
2365 {
2366 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
2367 }
2368 (*Count)++;
2369 }
2370 RtlFreeUnicodeString(&EntryFaceNameW);
2371 Entry = Entry->Flink;
2372 }
2373
2374 return TRUE;
2375 }
2376
2377 typedef struct FontFamilyInfoCallbackContext
2378 {
2379 LPLOGFONTW LogFont;
2380 PFONTFAMILYINFO Info;
2381 DWORD Count;
2382 DWORD Size;
2383 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
2384
2385 _Function_class_(RTL_QUERY_REGISTRY_ROUTINE)
2386 static NTSTATUS APIENTRY
2387 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
2388 IN PVOID ValueData, IN ULONG ValueLength,
2389 IN PVOID Context, IN PVOID EntryContext)
2390 {
2391 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
2392 UNICODE_STRING RegistryName, RegistryValue;
2393 int Existing;
2394 PFONTGDI FontGDI;
2395
2396 if (REG_SZ != ValueType)
2397 {
2398 return STATUS_SUCCESS;
2399 }
2400 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
2401 RtlInitUnicodeString(&RegistryName, ValueName);
2402
2403 /* Do we need to include this font family? */
2404 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
2405 min(InfoContext->Count, InfoContext->Size)))
2406 {
2407 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
2408 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
2409 min(InfoContext->Count, InfoContext->Size));
2410 if (0 <= Existing)
2411 {
2412 /* We already have the information about the "real" font. Just copy it */
2413 if (InfoContext->Count < InfoContext->Size)
2414 {
2415 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
2416 RtlStringCbCopyNW(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
2417 sizeof(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName),
2418 RegistryName.Buffer,
2419 RegistryName.Length);
2420 }
2421 InfoContext->Count++;
2422 return STATUS_SUCCESS;
2423 }
2424
2425 /* Try to find information about the "real" font */
2426 FontGDI = FindFaceNameInLists(&RegistryValue);
2427 if (NULL == FontGDI)
2428 {
2429 /* "Real" font not found, discard this registry entry */
2430 return STATUS_SUCCESS;
2431 }
2432
2433 /* Return info about the "real" font but with the name of the alias */
2434 if (InfoContext->Count < InfoContext->Size)
2435 {
2436 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
2437 RegistryName.Buffer, FontGDI);
2438 }
2439 InfoContext->Count++;
2440 return STATUS_SUCCESS;
2441 }
2442
2443 return STATUS_SUCCESS;
2444 }
2445
2446 static BOOLEAN FASTCALL
2447 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
2448 PFONTFAMILYINFO Info,
2449 DWORD *Count,
2450 DWORD Size)
2451 {
2452 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2453 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
2454 NTSTATUS Status;
2455
2456 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
2457 The real work is done in the registry callback function */
2458 Context.LogFont = LogFont;
2459 Context.Info = Info;
2460 Context.Count = *Count;
2461 Context.Size = Size;
2462
2463 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
2464 QueryTable[0].Flags = 0;
2465 QueryTable[0].Name = NULL;
2466 QueryTable[0].EntryContext = NULL;
2467 QueryTable[0].DefaultType = REG_NONE;
2468 QueryTable[0].DefaultData = NULL;
2469 QueryTable[0].DefaultLength = 0;
2470
2471 QueryTable[1].QueryRoutine = NULL;
2472 QueryTable[1].Name = NULL;
2473
2474 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2475 L"FontSubstitutes",
2476 QueryTable,
2477 &Context,
2478 NULL);
2479 if (NT_SUCCESS(Status))
2480 {
2481 *Count = Context.Count;
2482 }
2483
2484 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
2485 }
2486
2487 BOOL
2488 FASTCALL
2489 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
2490 {
2491 if ( lprs )
2492 {
2493 lprs->nSize = sizeof(RASTERIZER_STATUS);
2494 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
2495 lprs->nLanguageID = gusLanguageID;
2496 return TRUE;
2497 }
2498 EngSetLastError(ERROR_INVALID_PARAMETER);
2499 return FALSE;
2500 }
2501
2502 static
2503 BOOL
2504 SameScaleMatrix(
2505 PMATRIX pmx1,
2506 PMATRIX pmx2)
2507 {
2508 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
2509 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
2510 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
2511 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
2512 }
2513
2514 FT_BitmapGlyph APIENTRY
2515 ftGdiGlyphCacheGet(
2516 FT_Face Face,
2517 INT GlyphIndex,
2518 INT Height,
2519 PMATRIX pmx)
2520 {
2521 PLIST_ENTRY CurrentEntry;
2522 PFONT_CACHE_ENTRY FontEntry;
2523
2524 ASSERT_FREETYPE_LOCK_HELD();
2525
2526 CurrentEntry = FontCacheListHead.Flink;
2527 while (CurrentEntry != &FontCacheListHead)
2528 {
2529 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
2530 if ((FontEntry->Face == Face) &&
2531 (FontEntry->GlyphIndex == GlyphIndex) &&
2532 (FontEntry->Height == Height) &&
2533 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2534 break;
2535 CurrentEntry = CurrentEntry->Flink;
2536 }
2537
2538 if (CurrentEntry == &FontCacheListHead)
2539 {
2540 return NULL;
2541 }
2542
2543 RemoveEntryList(CurrentEntry);
2544 InsertHeadList(&FontCacheListHead, CurrentEntry);
2545 return FontEntry->BitmapGlyph;
2546 }
2547
2548 /* no cache */
2549 FT_BitmapGlyph APIENTRY
2550 ftGdiGlyphSet(
2551 FT_Face Face,
2552 FT_GlyphSlot GlyphSlot,
2553 FT_Render_Mode RenderMode)
2554 {
2555 FT_Glyph Glyph;
2556 INT error;
2557 FT_Bitmap AlignedBitmap;
2558 FT_BitmapGlyph BitmapGlyph;
2559
2560 error = FT_Get_Glyph(GlyphSlot, &Glyph);
2561 if (error)
2562 {
2563 DPRINT1("Failure getting glyph.\n");
2564 return NULL;
2565 }
2566
2567 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2568 if (error)
2569 {
2570 FT_Done_Glyph(Glyph);
2571 DPRINT1("Failure rendering glyph.\n");
2572 return NULL;
2573 }
2574
2575 BitmapGlyph = (FT_BitmapGlyph)Glyph;
2576 FT_Bitmap_New(&AlignedBitmap);
2577 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2578 {
2579 DPRINT1("Conversion failed\n");
2580 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2581 return NULL;
2582 }
2583
2584 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2585 BitmapGlyph->bitmap = AlignedBitmap;
2586
2587 return BitmapGlyph;
2588 }
2589
2590 FT_BitmapGlyph APIENTRY
2591 ftGdiGlyphCacheSet(
2592 FT_Face Face,
2593 INT GlyphIndex,
2594 INT Height,
2595 PMATRIX pmx,
2596 FT_GlyphSlot GlyphSlot,
2597 FT_Render_Mode RenderMode)
2598 {
2599 FT_Glyph GlyphCopy;
2600 INT error;
2601 PFONT_CACHE_ENTRY NewEntry;
2602 FT_Bitmap AlignedBitmap;
2603 FT_BitmapGlyph BitmapGlyph;
2604
2605 ASSERT_FREETYPE_LOCK_HELD();
2606
2607 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2608 if (error)
2609 {
2610 DPRINT1("Failure caching glyph.\n");
2611 return NULL;
2612 };
2613
2614 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2615 if (error)
2616 {
2617 FT_Done_Glyph(GlyphCopy);
2618 DPRINT1("Failure rendering glyph.\n");
2619 return NULL;
2620 };
2621
2622 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
2623 if (!NewEntry)
2624 {
2625 DPRINT1("Alloc failure caching glyph.\n");
2626 FT_Done_Glyph(GlyphCopy);
2627 return NULL;
2628 }
2629
2630 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2631 FT_Bitmap_New(&AlignedBitmap);
2632 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2633 {
2634 DPRINT1("Conversion failed\n");
2635 ExFreePoolWithTag(NewEntry, TAG_FONT);
2636 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2637 return NULL;
2638 }
2639
2640 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2641 BitmapGlyph->bitmap = AlignedBitmap;
2642
2643 NewEntry->GlyphIndex = GlyphIndex;
2644 NewEntry->Face = Face;
2645 NewEntry->BitmapGlyph = BitmapGlyph;
2646 NewEntry->Height = Height;
2647 NewEntry->mxWorldToDevice = *pmx;
2648
2649 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
2650 if (++FontCacheNumEntries > MAX_FONT_CACHE)
2651 {
2652 NewEntry = CONTAINING_RECORD(FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
2653 RemoveCachedEntry(NewEntry);
2654 }
2655
2656 return BitmapGlyph;
2657 }
2658
2659
2660 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2661 {
2662 pt->x.value = vec->x >> 6;
2663 pt->x.fract = (vec->x & 0x3f) << 10;
2664 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2665 pt->y.value = vec->y >> 6;
2666 pt->y.fract = (vec->y & 0x3f) << 10;
2667 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2668 }
2669
2670 /*
2671 This function builds an FT_Fixed from a float. It puts the integer part
2672 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2673 It fails if the integer part of the float number is greater than SHORT_MAX.
2674 */
2675 static __inline FT_Fixed FT_FixedFromFloat(float f)
2676 {
2677 short value = f;
2678 unsigned short fract = (f - value) * 0xFFFF;
2679 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2680 }
2681
2682 /*
2683 This function builds an FT_Fixed from a FIXED. It simply put f.value
2684 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2685 */
2686 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2687 {
2688 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2689 }
2690
2691 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2692 {
2693 TTPOLYGONHEADER *pph;
2694 TTPOLYCURVE *ppc;
2695 int needed = 0, point = 0, contour, first_pt;
2696 unsigned int pph_start, cpfx;
2697 DWORD type;
2698
2699 for (contour = 0; contour < outline->n_contours; contour++)
2700 {
2701 /* Ignore contours containing one point */
2702 if (point == outline->contours[contour])
2703 {
2704 point++;
2705 continue;
2706 }
2707
2708 pph_start = needed;
2709 pph = (TTPOLYGONHEADER *)(buf + needed);
2710 first_pt = point;
2711 if (buf)
2712 {
2713 pph->dwType = TT_POLYGON_TYPE;
2714 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2715 }
2716 needed += sizeof(*pph);
2717 point++;
2718 while (point <= outline->contours[contour])
2719 {
2720 ppc = (TTPOLYCURVE *)(buf + needed);
2721 type = outline->tags[point] & FT_Curve_Tag_On ?
2722 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2723 cpfx = 0;
2724 do
2725 {
2726 if (buf)
2727 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2728 cpfx++;
2729 point++;
2730 } while (point <= outline->contours[contour] &&
2731 (outline->tags[point] & FT_Curve_Tag_On) ==
2732 (outline->tags[point-1] & FT_Curve_Tag_On));
2733 /* At the end of a contour Windows adds the start point, but
2734 only for Beziers */
2735 if (point > outline->contours[contour] &&
2736 !(outline->tags[point-1] & FT_Curve_Tag_On))
2737 {
2738 if (buf)
2739 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2740 cpfx++;
2741 }
2742 else if (point <= outline->contours[contour] &&
2743 outline->tags[point] & FT_Curve_Tag_On)
2744 {
2745 /* add closing pt for bezier */
2746 if (buf)
2747 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2748 cpfx++;
2749 point++;
2750 }
2751 if (buf)
2752 {
2753 ppc->wType = type;
2754 ppc->cpfx = cpfx;
2755 }
2756 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2757 }
2758 if (buf)
2759 pph->cb = needed - pph_start;
2760 }
2761 return needed;
2762 }
2763
2764 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2765 {
2766 /* Convert the quadratic Beziers to cubic Beziers.
2767 The parametric eqn for a cubic Bezier is, from PLRM:
2768 r(t) = at^3 + bt^2 + ct + r0
2769 with the control points:
2770 r1 = r0 + c/3
2771 r2 = r1 + (c + b)/3
2772 r3 = r0 + c + b + a
2773
2774 A quadratic Bezier has the form:
2775 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2776
2777 So equating powers of t leads to:
2778 r1 = 2/3 p1 + 1/3 p0
2779 r2 = 2/3 p1 + 1/3 p2
2780 and of course r0 = p0, r3 = p2
2781 */
2782 int contour, point = 0, first_pt;
2783 TTPOLYGONHEADER *pph;
2784 TTPOLYCURVE *ppc;
2785 DWORD pph_start, cpfx, type;
2786 FT_Vector cubic_control[4];
2787 unsigned int needed = 0;
2788
2789 for (contour = 0; contour < outline->n_contours; contour++)
2790 {
2791 pph_start = needed;
2792 pph = (TTPOLYGONHEADER *)(buf + needed);
2793 first_pt = point;
2794 if (buf)
2795 {
2796 pph->dwType = TT_POLYGON_TYPE;
2797 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2798 }
2799 needed += sizeof(*pph);
2800 point++;
2801 while (point <= outline->contours[contour])
2802 {
2803 ppc = (TTPOLYCURVE *)(buf + needed);
2804 type = outline->tags[point] & FT_Curve_Tag_On ?
2805 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2806 cpfx = 0;
2807 do
2808 {
2809 if (type == TT_PRIM_LINE)
2810 {
2811 if (buf)
2812 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2813 cpfx++;
2814 point++;
2815 }
2816 else
2817 {
2818 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2819 so cpfx = 3n */
2820
2821 /* FIXME: Possible optimization in endpoint calculation
2822 if there are two consecutive curves */
2823 cubic_control[0] = outline->points[point-1];
2824 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2825 {
2826 cubic_control[0].x += outline->points[point].x + 1;
2827 cubic_control[0].y += outline->points[point].y + 1;
2828 cubic_control[0].x >>= 1;
2829 cubic_control[0].y >>= 1;
2830 }
2831 if (point+1 > outline->contours[contour])
2832 cubic_control[3] = outline->points[first_pt];
2833 else
2834 {
2835 cubic_control[3] = outline->points[point+1];
2836 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2837 {
2838 cubic_control[3].x += outline->points[point].x + 1;
2839 cubic_control[3].y += outline->points[point].y + 1;
2840 cubic_control[3].x >>= 1;
2841 cubic_control[3].y >>= 1;
2842 }
2843 }
2844 /* r1 = 1/3 p0 + 2/3 p1
2845 r2 = 1/3 p2 + 2/3 p1 */
2846 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2847 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2848 cubic_control[2] = cubic_control[1];
2849 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2850 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2851 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2852 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2853 if (buf)
2854 {
2855 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2856 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2857 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2858 }
2859 cpfx += 3;
2860 point++;
2861 }
2862 } while (point <= outline->contours[contour] &&
2863 (outline->tags[point] & FT_Curve_Tag_On) ==
2864 (outline->tags[point-1] & FT_Curve_Tag_On));
2865 /* At the end of a contour Windows adds the start point,
2866 but only for Beziers and we've already done that.
2867 */
2868 if (point <= outline->contours[contour] &&
2869 outline->tags[point] & FT_Curve_Tag_On)
2870 {
2871 /* This is the closing pt of a bezier, but we've already
2872 added it, so just inc point and carry on */
2873 point++;
2874 }
2875 if (buf)
2876 {
2877 ppc->wType = type;
2878 ppc->cpfx = cpfx;
2879 }
2880 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2881 }
2882 if (buf)
2883 pph->cb = needed - pph_start;
2884 }
2885 return needed;
2886 }
2887
2888 static INT
2889 IntRequestFontSize(PDC dc, FT_Face face, LONG Width, LONG Height)
2890 {
2891 FT_Size_RequestRec req;
2892
2893 if (Width < 0)
2894 Width = -Width;
2895
2896 if (Height < 0)
2897 {
2898 Height = -Height;
2899 }
2900 if (Height == 0)
2901 {
2902 Height = dc->ppdev->devinfo.lfDefaultFont.lfHeight;
2903 }
2904 if (Height == 0)
2905 {
2906 Height = Width;
2907 }
2908
2909 if (Height < 1)
2910 Height = 1;
2911
2912 if (Width > 0xFFFFU)
2913 Width = 0xFFFFU;
2914 if (Height > 0xFFFFU)
2915 Height = 0xFFFFU;
2916
2917 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
2918 req.width = (FT_Long)(Width << 6);
2919 req.height = (FT_Long)(Height << 6);
2920 req.horiResolution = 0;
2921 req.vertResolution = 0;
2922 return FT_Request_Size(face, &req);
2923 }
2924
2925 BOOL
2926 FASTCALL
2927 TextIntUpdateSize(PDC dc,
2928 PTEXTOBJ TextObj,
2929 PFONTGDI FontGDI,
2930 BOOL bDoLock)
2931 {
2932 FT_Face face;
2933 INT error, n;
2934 FT_CharMap charmap, found;
2935 LOGFONTW *plf;
2936
2937 if (bDoLock)
2938 IntLockFreeType;
2939
2940 face = FontGDI->SharedFace->Face;
2941 if (face->charmap == NULL)
2942 {
2943 DPRINT("WARNING: No charmap selected!\n");
2944 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2945
2946 found = NULL;
2947 for (n = 0; n < face->num_charmaps; n++)
2948 {
2949 charmap = face->charmaps[n];
2950 DPRINT("Found charmap encoding: %i\n", charmap->encoding);
2951 if (charmap->encoding != 0)
2952 {
2953 found = charmap;
2954 break;
2955 }
2956 }
2957 if (!found)
2958 {
2959 DPRINT1("WARNING: Could not find desired charmap!\n");
2960 }
2961 else
2962 {
2963 error = FT_Set_Charmap(face, found);
2964 if (error)
2965 {
2966 DPRINT1("WARNING: Could not set the charmap!\n");
2967 }
2968 }
2969 }
2970
2971 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
2972
2973 error = IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
2974
2975 if (bDoLock)
2976 IntUnLockFreeType;
2977
2978 if (error)
2979 {
2980 DPRINT1("Error in setting pixel sizes: %d\n", error);
2981 return FALSE;
2982 }
2983
2984 return TRUE;
2985 }
2986
2987
2988 /*
2989 * Based on WineEngGetGlyphOutline
2990 *
2991 */
2992 ULONG
2993 FASTCALL
2994 ftGdiGetGlyphOutline(
2995 PDC dc,
2996 WCHAR wch,
2997 UINT iFormat,
2998 LPGLYPHMETRICS pgm,
2999 ULONG cjBuf,
3000 PVOID pvBuf,
3001 LPMAT2 pmat2,
3002 BOOL bIgnoreRotation)
3003 {
3004 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3005 PDC_ATTR pdcattr;
3006 PTEXTOBJ TextObj;
3007 PFONTGDI FontGDI;
3008 HFONT hFont = 0;
3009 GLYPHMETRICS gm;
3010 ULONG Size;
3011 FT_Face ft_face;
3012 FT_UInt glyph_index;
3013 DWORD width, height, pitch, needed = 0;
3014 FT_Bitmap ft_bitmap;
3015 FT_Error error;
3016 INT left, right, top = 0, bottom = 0;
3017 FT_Angle angle = 0;
3018 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3019 FLOAT eM11, widthRatio = 1.0;
3020 FT_Matrix transMat = identityMat;
3021 BOOL needsTransform = FALSE;
3022 INT orientation;
3023 LONG aveWidth;
3024 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3025 OUTLINETEXTMETRICW *potm;
3026 XFORM xForm;
3027 LOGFONTW *plf;
3028
3029 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3030 cjBuf, pvBuf, pmat2);
3031
3032 pdcattr = dc->pdcattr;
3033
3034 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
3035 eM11 = xForm.eM11;
3036
3037 hFont = pdcattr->hlfntNew;
3038 TextObj = RealizeFontInit(hFont);
3039
3040 if (!TextObj)
3041 {
3042 EngSetLastError(ERROR_INVALID_HANDLE);
3043 return GDI_ERROR;
3044 }
3045 FontGDI = ObjToGDI(TextObj->Font, FONT);
3046 ft_face = FontGDI->SharedFace->Face;
3047
3048 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3049 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3050 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3051
3052 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3053 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3054 if (!potm)
3055 {
3056 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3057 TEXTOBJ_UnlockText(TextObj);
3058 return GDI_ERROR;
3059 }
3060 IntGetOutlineTextMetrics(FontGDI, Size, potm);
3061
3062 IntLockFreeType;
3063 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3064 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
3065
3066 TEXTOBJ_UnlockText(TextObj);
3067
3068 if (iFormat & GGO_GLYPH_INDEX)
3069 {
3070 glyph_index = wch;
3071 iFormat &= ~GGO_GLYPH_INDEX;
3072 }
3073 else glyph_index = FT_Get_Char_Index(ft_face, wch);
3074
3075 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3076 load_flags |= FT_LOAD_NO_BITMAP;
3077
3078 if (iFormat & GGO_UNHINTED)
3079 {
3080 load_flags |= FT_LOAD_NO_HINTING;
3081 iFormat &= ~GGO_UNHINTED;
3082 }
3083
3084 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3085 if (error)
3086 {
3087 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3088 IntUnLockFreeType;
3089 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3090 return GDI_ERROR;
3091 }
3092 IntUnLockFreeType;
3093
3094 if (aveWidth && potm)
3095 {
3096 widthRatio = (FLOAT)aveWidth * eM11 /
3097 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
3098 }
3099
3100 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3101 right = (INT)((ft_face->glyph->metrics.horiBearingX +
3102 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3103
3104 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3105 lsb = left >> 6;
3106 bbx = (right - left) >> 6;
3107
3108 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3109
3110 IntLockFreeType;
3111
3112 /* Scaling transform */
3113 /*if (aveWidth)*/
3114 {
3115
3116 FT_Matrix ftmatrix;
3117 FLOATOBJ efTemp;
3118
3119 PMATRIX pmx = DC_pmxWorldToDevice(dc);
3120
3121 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3122 efTemp = pmx->efM11;
3123 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3124 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
3125
3126 efTemp = pmx->efM12;
3127 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3128 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
3129
3130 efTemp = pmx->efM21;
3131 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3132 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
3133
3134 efTemp = pmx->efM22;
3135 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3136 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
3137
3138 FT_Matrix_Multiply(&ftmatrix, &transMat);
3139 needsTransform = TRUE;
3140 }
3141
3142 /* Rotation transform */
3143 if (orientation)
3144 {
3145 FT_Matrix rotationMat;
3146 FT_Vector vecAngle;
3147 DPRINT("Rotation Trans!\n");
3148 angle = FT_FixedFromFloat((float)orientation / 10.0);
3149 FT_Vector_Unit(&vecAngle, angle);
3150 rotationMat.xx = vecAngle.x;
3151 rotationMat.xy = -vecAngle.y;
3152 rotationMat.yx = -rotationMat.xy;
3153 rotationMat.yy = rotationMat.xx;
3154 FT_Matrix_Multiply(&rotationMat, &transMat);
3155 needsTransform = TRUE;
3156 }
3157
3158 /* Extra transformation specified by caller */
3159 if (pmat2)
3160 {
3161 FT_Matrix extraMat;
3162 DPRINT("MAT2 Matrix Trans!\n");
3163 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
3164 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
3165 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
3166 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
3167 FT_Matrix_Multiply(&extraMat, &transMat);
3168 needsTransform = TRUE;
3169 }
3170
3171 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
3172
3173 if (!needsTransform)
3174 {
3175 DPRINT("No Need to be Transformed!\n");
3176 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3177 bottom = (ft_face->glyph->metrics.horiBearingY -
3178 ft_face->glyph->metrics.height) & -64;
3179 gm.gmCellIncX = adv;
3180 gm.gmCellIncY = 0;
3181 }
3182 else
3183 {
3184 INT xc, yc;
3185 FT_Vector vec;
3186 for (xc = 0; xc < 2; xc++)
3187 {
3188 for (yc = 0; yc < 2; yc++)
3189 {
3190 vec.x = (ft_face->glyph->metrics.horiBearingX +
3191 xc * ft_face->glyph->metrics.width);
3192 vec.y = ft_face->glyph->metrics.horiBearingY -
3193 yc * ft_face->glyph->metrics.height;
3194 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
3195 FT_Vector_Transform(&vec, &transMat);
3196 if (xc == 0 && yc == 0)
3197 {
3198 left = right = vec.x;
3199 top = bottom = vec.y;
3200 }
3201 else
3202 {
3203 if (vec.x < left) left = vec.x;
3204 else if (vec.x > right) right = vec.x;
3205 if (vec.y < bottom) bottom = vec.y;
3206 else if (vec.y > top) top = vec.y;
3207 }
3208 }
3209 }
3210 left = left & -64;
3211 right = (right + 63) & -64;
3212 bottom = bottom & -64;
3213 top = (top + 63) & -64;
3214
3215 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3216 vec.x = ft_face->glyph->metrics.horiAdvance;
3217 vec.y = 0;
3218 FT_Vector_Transform(&vec, &transMat);
3219 gm.gmCellIncX = (vec.x+63) >> 6;
3220 gm.gmCellIncY = -((vec.y+63) >> 6);
3221 }
3222 gm.gmBlackBoxX = (right - left) >> 6;
3223 gm.gmBlackBoxY = (top - bottom) >> 6;
3224 gm.gmptGlyphOrigin.x = left >> 6;
3225 gm.gmptGlyphOrigin.y = top >> 6;
3226
3227 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
3228 gm.gmCellIncX, gm.gmCellIncY,
3229 gm.gmBlackBoxX, gm.gmBlackBoxY,
3230 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
3231
3232 IntUnLockFreeType;
3233
3234
3235 if (iFormat == GGO_METRICS)
3236 {
3237 DPRINT("GGO_METRICS Exit!\n");
3238 *pgm = gm;
3239 return 1; /* FIXME */
3240 }
3241
3242 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
3243 {
3244 DPRINT1("Loaded a bitmap\n");
3245 return GDI_ERROR;
3246 }
3247
3248 switch (iFormat)
3249 {
3250 case GGO_BITMAP:
3251 width = gm.gmBlackBoxX;
3252 height = gm.gmBlackBoxY;
3253 pitch = ((width + 31) >> 5) << 2;
3254 needed = pitch * height;
3255
3256 if (!pvBuf || !cjBuf) break;
3257 if (!needed) return GDI_ERROR; /* empty glyph */
3258 if (needed > cjBuf)
3259 return GDI_ERROR;
3260
3261 switch (ft_face->glyph->format)
3262 {
3263 case ft_glyph_format_bitmap:
3264 {
3265 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3266 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
3267 INT h = min( height, ft_face->glyph->bitmap.rows );
3268 while (h--)
3269 {
3270 RtlCopyMemory(dst, src, w);
3271 src += ft_face->glyph->bitmap.pitch;
3272 dst += pitch;
3273 }
3274 break;
3275 }
3276
3277 case ft_glyph_format_outline:
3278 ft_bitmap.width = width;
3279 ft_bitmap.rows = height;
3280 ft_bitmap.pitch = pitch;
3281 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
3282 ft_bitmap.buffer = pvBuf;
3283
3284 IntLockFreeType;
3285 if (needsTransform)
3286 {
3287 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3288 }
3289 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3290 /* Note: FreeType will only set 'black' bits for us. */
3291 RtlZeroMemory(pvBuf, needed);
3292 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3293 IntUnLockFreeType;
3294 break;
3295
3296 default:
3297 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3298 return GDI_ERROR;
3299 }
3300 break;
3301
3302 case GGO_GRAY2_BITMAP:
3303 case GGO_GRAY4_BITMAP:
3304 case GGO_GRAY8_BITMAP:
3305 {
3306 unsigned int mult, row, col;
3307 BYTE *start, *ptr;
3308
3309 width = gm.gmBlackBoxX;
3310 height = gm.gmBlackBoxY;
3311 pitch = (width + 3) / 4 * 4;
3312 needed = pitch * height;
3313
3314 if (!pvBuf || !cjBuf) break;
3315 if (!needed) return GDI_ERROR; /* empty glyph */
3316 if (needed > cjBuf)
3317 return GDI_ERROR;
3318
3319 switch (ft_face->glyph->format)
3320 {
3321 case ft_glyph_format_bitmap:
3322 {
3323 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3324 INT h = min( height, ft_face->glyph->bitmap.rows );
3325 INT x;
3326 while (h--)
3327 {
3328 for (x = 0; (UINT)x < pitch; x++)
3329 {
3330 if (x < ft_face->glyph->bitmap.width)
3331 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3332 else
3333 dst[x] = 0;
3334 }
3335 src += ft_face->glyph->bitmap.pitch;
3336 dst += pitch;
3337 }
3338 break;
3339 }
3340 case ft_glyph_format_outline:
3341 {
3342 ft_bitmap.width = width;
3343 ft_bitmap.rows = height;
3344 ft_bitmap.pitch = pitch;
3345 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3346 ft_bitmap.buffer = pvBuf;
3347
3348 IntLockFreeType;
3349 if (needsTransform)
3350 {
3351 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3352 }
3353 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3354 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
3355 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3356 IntUnLockFreeType;
3357
3358 if (iFormat == GGO_GRAY2_BITMAP)
3359 mult = 4;
3360 else if (iFormat == GGO_GRAY4_BITMAP)
3361 mult = 16;
3362 else if (iFormat == GGO_GRAY8_BITMAP)
3363 mult = 64;
3364 else
3365 {
3366 return GDI_ERROR;
3367 }
3368
3369 start = pvBuf;
3370 for (row = 0; row < height; row++)
3371 {
3372 ptr = start;
3373 for (col = 0; col < width; col++, ptr++)
3374 {
3375 *ptr = (((int)*ptr) * mult + 128) / 256;
3376 }
3377 start += pitch;
3378 }
3379
3380 break;
3381 }
3382 default:
3383 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3384 return GDI_ERROR;
3385 }
3386 }
3387
3388 case GGO_NATIVE:
3389 {
3390 FT_Outline *outline = &ft_face->glyph->outline;
3391
3392 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
3393
3394 IntLockFreeType;
3395 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
3396
3397 needed = get_native_glyph_outline(outline, cjBuf, NULL);
3398
3399 if (!pvBuf || !cjBuf)
3400 {
3401 IntUnLockFreeType;
3402 break;
3403 }
3404 if (needed > cjBuf)
3405 {
3406 IntUnLockFreeType;
3407 return GDI_ERROR;
3408 }
3409 get_native_glyph_outline(outline, cjBuf, pvBuf);
3410 IntUnLockFreeType;
3411 break;
3412 }
3413 case GGO_BEZIER:
3414 {
3415 FT_Outline *outline = &ft_face->glyph->outline;
3416 if (cjBuf == 0) pvBuf = NULL;
3417
3418 if (needsTransform && pvBuf)
3419 {
3420 IntLockFreeType;
3421 FT_Outline_Transform(outline, &transMat);
3422 IntUnLockFreeType;
3423 }
3424 needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
3425
3426 if (!pvBuf || !cjBuf)
3427 break;
3428 if (needed > cjBuf)
3429 return GDI_ERROR;
3430
3431 get_bezier_glyph_outline(outline, cjBuf, pvBuf);
3432 break;
3433 }
3434
3435 default:
3436 DPRINT1("Unsupported format %u\n", iFormat);
3437 return GDI_ERROR;
3438 }
3439
3440 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
3441 *pgm = gm;
3442 return needed;
3443 }
3444
3445 BOOL
3446 FASTCALL
3447 TextIntGetTextExtentPoint(PDC dc,
3448 PTEXTOBJ TextObj,
3449 LPCWSTR String,
3450 INT Count,
3451 ULONG MaxExtent,
3452 LPINT Fit,
3453 LPINT Dx,
3454 LPSIZE Size,
3455 FLONG fl)
3456 {
3457 PFONTGDI FontGDI;
3458 FT_Face face;
3459 FT_GlyphSlot glyph;
3460 FT_BitmapGlyph realglyph;
3461 INT error, glyph_index, i, previous;
3462 ULONGLONG TotalWidth = 0;
3463 BOOL use_kerning;
3464 FT_Render_Mode RenderMode;
3465 BOOLEAN Render;
3466 PMATRIX pmxWorldToDevice;
3467 LOGFONTW *plf;
3468 BOOL EmuBold, EmuItalic;
3469
3470 FontGDI = ObjToGDI(TextObj->Font, FONT);
3471
3472 face = FontGDI->SharedFace->Face;
3473 if (NULL != Fit)
3474 {
3475 *Fit = 0;
3476 }
3477
3478 IntLockFreeType;
3479
3480 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3481
3482 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3483 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
3484 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
3485
3486 Render = IntIsFontRenderingEnabled();
3487 if (Render)
3488 RenderMode = IntGetFontRenderMode(plf);
3489 else
3490 RenderMode = FT_RENDER_MODE_MONO;
3491
3492
3493 /* Get the DC's world-to-device transformation matrix */
3494 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3495 FtSetCoordinateTransform(face, pmxWorldToDevice);
3496
3497 use_kerning = FT_HAS_KERNING(face);
3498 previous = 0;
3499
3500 for (i = 0; i < Count; i++)
3501 {
3502 if (fl & GTEF_INDICES)
3503 glyph_index = *String;
3504 else
3505 glyph_index = FT_Get_Char_Index(face, *String);
3506
3507 if (EmuBold || EmuItalic)
3508 realglyph = NULL;
3509 else
3510 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3511 plf->lfHeight, pmxWorldToDevice);
3512
3513 if (EmuBold || EmuItalic || !realglyph)
3514 {
3515 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3516 if (error)
3517 {
3518 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
3519 break;
3520 }
3521
3522 glyph = face->glyph;
3523 if (EmuBold || EmuItalic)
3524 {
3525 if (EmuBold)
3526 FT_GlyphSlot_Embolden(glyph);
3527 if (EmuItalic)
3528 FT_GlyphSlot_Oblique(glyph);
3529 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
3530 }
3531 else
3532 {
3533 realglyph = ftGdiGlyphCacheSet(face,
3534 glyph_index,
3535 plf->lfHeight,
3536 pmxWorldToDevice,
3537 glyph,
3538 RenderMode);
3539 }
3540
3541 if (!realglyph)
3542 {
3543 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3544 break;
3545 }
3546 }
3547
3548 /* Retrieve kerning distance */
3549 if (use_kerning && previous && glyph_index)
3550 {
3551 FT_Vector delta;
3552 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3553 TotalWidth += delta.x;
3554 }
3555
3556 TotalWidth += realglyph->root.advance.x >> 10;
3557
3558 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
3559 {
3560 *Fit = i + 1;
3561 }
3562 if (NULL != Dx)
3563 {
3564 Dx[i] = (TotalWidth + 32) >> 6;
3565 }
3566
3567 if (EmuBold || EmuItalic)
3568 {
3569 FT_Done_Glyph((FT_Glyph)realglyph);
3570 realglyph = NULL;
3571 }
3572
3573 previous = glyph_index;
3574 String++;
3575 }
3576 IntUnLockFreeType;
3577
3578 Size->cx = (TotalWidth + 32) >> 6;
3579 Size->cy = (plf->lfHeight == 0 ?
3580 dc->ppdev->devinfo.lfDefaultFont.lfHeight :
3581 abs(plf->lfHeight));
3582 Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
3583
3584 return TRUE;
3585 }
3586
3587
3588 INT
3589 FASTCALL
3590 ftGdiGetTextCharsetInfo(
3591 PDC Dc,
3592 LPFONTSIGNATURE lpSig,
3593 DWORD dwFlags)
3594 {
3595 PDC_ATTR pdcattr;
3596 UINT Ret = DEFAULT_CHARSET;
3597 INT i;
3598 HFONT hFont;
3599 PTEXTOBJ TextObj;
3600 PFONTGDI FontGdi;
3601 FONTSIGNATURE fs;
3602 TT_OS2 *pOS2;
3603 FT_Face Face;
3604 CHARSETINFO csi;
3605 DWORD cp, fs0;
3606 USHORT usACP, usOEM;
3607
3608 pdcattr = Dc->pdcattr;
3609 hFont = pdcattr->hlfntNew;
3610 TextObj = RealizeFontInit(hFont);
3611
3612 if (!TextObj)
3613 {
3614 EngSetLastError(ERROR_INVALID_HANDLE);
3615 return Ret;
3616 }
3617 FontGdi = ObjToGDI(TextObj->Font, FONT);
3618 Face = FontGdi->SharedFace->Face;
3619 TEXTOBJ_UnlockText(TextObj);
3620
3621 IntLockFreeType;
3622 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3623 IntUnLockFreeType;
3624 memset(&fs, 0, sizeof(FONTSIGNATURE));
3625 if (NULL != pOS2)
3626 {
3627 fs.fsCsb[0] = pOS2->ulCodePageRange1;
3628 fs.fsCsb[1] = pOS2->ulCodePageRange2;
3629 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3630 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3631 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3632 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3633 if (pOS2->version == 0)
3634 {
3635 FT_UInt dummy;
3636
3637 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
3638 fs.fsCsb[0] |= FS_LATIN1;
3639 else
3640 fs.fsCsb[0] |= FS_SYMBOL;
3641 }
3642 }
3643 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
3644 if (fs.fsCsb[0] == 0)
3645 { /* Let's see if we can find any interesting cmaps */
3646 for (i = 0; i < Face->num_charmaps; i++)
3647 {
3648 switch (Face->charmaps[i]->encoding)
3649 {
3650 case FT_ENCODING_UNICODE:
3651 case FT_ENCODING_APPLE_ROMAN:
3652 fs.fsCsb[0] |= FS_LATIN1;
3653 break;
3654 case FT_ENCODING_MS_SYMBOL:
3655 fs.fsCsb[0] |= FS_SYMBOL;
3656 break;
3657 default:
3658 break;
3659 }
3660 }
3661 }
3662 if (lpSig)
3663 {
3664 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
3665 }
3666
3667 RtlGetDefaultCodePage(&usACP, &usOEM);
3668 cp = usACP;
3669
3670 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
3671 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
3672 {
3673 DPRINT("Hit 1\n");
3674 Ret = csi.ciCharset;
3675 goto Exit;
3676 }
3677
3678 for (i = 0; i < MAXTCIINDEX; i++)
3679 {
3680 fs0 = 1L << i;
3681 if (fs.fsCsb[0] & fs0)
3682 {
3683 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
3684 {
3685 // *cp = csi.ciACP;
3686 DPRINT("Hit 2\n");
3687 Ret = csi.ciCharset;
3688 goto Exit;
3689 }
3690 else
3691 DPRINT1("TCI failing on %x\n", fs0);
3692 }
3693 }
3694 Exit:
3695 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
3696 return (MAKELONG(csi.ciACP, csi.ciCharset));
3697 }
3698
3699
3700 DWORD
3701 FASTCALL
3702 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
3703 {
3704 DWORD size = 0;
3705 DWORD num_ranges = 0;
3706 FT_Face face = Font->SharedFace->Face;
3707
3708 if (face->charmap->encoding == FT_ENCODING_UNICODE)
3709 {
3710 FT_UInt glyph_code = 0;
3711 FT_ULong char_code, char_code_prev;
3712
3713 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
3714
3715 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3716 face->num_glyphs, glyph_code, char_code);
3717
3718 if (!glyph_code) return 0;
3719
3720 if (glyphset)
3721 {
3722 glyphset->ranges[0].wcLow = (USHORT)char_code;
3723 glyphset->ranges[0].cGlyphs = 0;
3724 glyphset->cGlyphsSupported = 0;
3725 }
3726
3727 num_ranges = 1;
3728 while (glyph_code)
3729 {
3730 if (char_code < char_code_prev)
3731 {
3732 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
3733 return 0;
3734 }
3735 if (char_code - char_code_prev > 1)
3736 {
3737 num_ranges++;
3738 if (glyphset)
3739 {
3740 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
3741 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
3742 glyphset->cGlyphsSupported++;
3743 }
3744 }
3745 else if (glyphset)
3746 {
3747 glyphset->ranges[num_ranges - 1].cGlyphs++;
3748 glyphset->cGlyphsSupported++;
3749 }
3750 char_code_prev = char_code;
3751 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
3752 }
3753 }
3754 else
3755 DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
3756
3757 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
3758 if (glyphset)
3759 {
3760 glyphset->cbThis = size;
3761 glyphset->cRanges = num_ranges;
3762 glyphset->flAccel = 0;
3763 }
3764 return size;
3765 }
3766
3767
3768 BOOL
3769 FASTCALL
3770 ftGdiGetTextMetricsW(
3771 HDC hDC,
3772 PTMW_INTERNAL ptmwi)
3773 {
3774 PDC dc;
3775 PDC_ATTR pdcattr;
3776 PTEXTOBJ TextObj;
3777 PFONTGDI FontGDI;
3778 FT_Face Face;
3779 TT_OS2 *pOS2;
3780 TT_HoriHeader *pHori;
3781 FT_WinFNT_HeaderRec Win;
3782 ULONG Error;
3783 NTSTATUS Status = STATUS_SUCCESS;
3784 LOGFONTW *plf;
3785
3786 if (!ptmwi)
3787 {
3788 EngSetLastError(STATUS_INVALID_PARAMETER);
3789 return FALSE;
3790 }
3791
3792 if (!(dc = DC_LockDc(hDC)))
3793 {
3794 EngSetLastError(ERROR_INVALID_HANDLE);
3795 return FALSE;
3796 }
3797 pdcattr = dc->pdcattr;
3798 TextObj = RealizeFontInit(pdcattr->hlfntNew);
3799 if (NULL != TextObj)
3800 {
3801 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3802 FontGDI = ObjToGDI(TextObj->Font, FONT);
3803
3804 Face = FontGDI->SharedFace->Face;
3805 IntLockFreeType;
3806 Error = IntRequestFontSize(dc, Face, plf->lfWidth, plf->lfHeight);
3807 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
3808 IntUnLockFreeType;
3809 if (0 != Error)
3810 {
3811 DPRINT1("Error in setting pixel sizes: %u\n", Error);
3812 Status = STATUS_UNSUCCESSFUL;
3813 }
3814 else
3815 {
3816 FT_Face Face = FontGDI->SharedFace->Face;
3817 Status = STATUS_SUCCESS;
3818
3819 IntLockFreeType;
3820 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3821 if (NULL == pOS2)
3822 {
3823 DPRINT1("Can't find OS/2 table - not TT font?\n");
3824 Status = STATUS_INTERNAL_ERROR;
3825 }
3826
3827 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
3828 if (NULL == pHori)
3829 {
3830 DPRINT1("Can't find HHEA table - not TT font?\n");
3831 Status = STATUS_INTERNAL_ERROR;
3832 }
3833
3834 Error = FT_Get_WinFNT_Header(Face, &Win);
3835
3836 IntUnLockFreeType;
3837
3838 if (NT_SUCCESS(Status))
3839 {
3840 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
3841
3842 /* FIXME: Fill Diff member */
3843 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
3844 }
3845 }
3846 TEXTOBJ_UnlockText(TextObj);
3847 }
3848 else
3849 {
3850 Status = STATUS_INVALID_HANDLE;
3851 }
3852 DC_UnlockDc(dc);
3853
3854 if (!NT_SUCCESS(Status))
3855 {
3856 SetLastNtError(Status);
3857 return FALSE;
3858 }
3859 return TRUE;
3860 }
3861
3862 DWORD
3863 FASTCALL
3864 ftGdiGetFontData(
3865 PFONTGDI FontGdi,
3866 DWORD Table,
3867 DWORD Offset,
3868 PVOID Buffer,
3869 DWORD Size)
3870 {
3871 DWORD Result = GDI_ERROR;
3872 FT_Face Face = FontGdi->SharedFace->Face;
3873
3874 IntLockFreeType;
3875
3876 if (FT_IS_SFNT(Face))
3877 {
3878 if (Table)
3879 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
3880 (Table << 8 & 0xFF0000);
3881
3882 if (!Buffer) Size = 0;
3883
3884 if (Buffer && Size)
3885 {
3886 FT_Error Error;
3887 FT_ULong Needed = 0;
3888
3889 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
3890
3891 if ( !Error && Needed < Size) Size = Needed;
3892 }
3893 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
3894 Result = Size;
3895 }
3896
3897 IntUnLockFreeType;
3898
3899 return Result;
3900 }
3901
3902 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
3903 static UINT FASTCALL
3904 GetFontPenalty(LOGFONTW * LogFont,
3905 PUNICODE_STRING RequestedNameW,
3906 PUNICODE_STRING ActualNameW,
3907 PUNICODE_STRING FullFaceNameW,
3908 BYTE RequestedCharSet,
3909 PFONTGDI FontGDI,
3910 OUTLINETEXTMETRICW * Otm,
3911 TEXTMETRICW * TM,
3912 const char * style_name)
3913 {
3914 ULONG Penalty = 0;
3915 BYTE Byte;
3916 LONG Long;
3917 BOOL fFixedSys = FALSE, fNeedScaling = FALSE;
3918 const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
3919
3920 /* FIXME: Aspect Penalty 30 */
3921 /* FIXME: IntSizeSynth Penalty 20 */
3922 /* FIXME: SmallPenalty Penalty 1 */
3923 /* FIXME: FaceNameSubst Penalty 500 */
3924
3925 if (RtlEqualUnicodeString(RequestedNameW, &SystemW, TRUE))
3926 {
3927 /* "System" font */
3928 if (TM->tmCharSet != UserCharSet)
3929 {
3930 /* CharSet Penalty 65000 */
3931 /* Requested charset does not match the candidate's. */
3932 Penalty += 65000;
3933 }
3934 }
3935 else if (RtlEqualUnicodeString(RequestedNameW, &FixedSysW, TRUE))
3936 {
3937 /* "FixedSys" font */
3938 if (TM->tmCharSet != UserCharSet)
3939 {
3940 /* CharSet Penalty 65000 */
3941 /* Requested charset does not match the candidate's. */
3942 Penalty += 65000;
3943 }
3944 fFixedSys = TRUE;
3945 }
3946 else /* Request is non-"System" font */
3947 {
3948 Byte = RequestedCharSet;
3949 if (Byte == DEFAULT_CHARSET)
3950 {
3951 if (RtlEqualUnicodeString(RequestedNameW, &MarlettW, TRUE))
3952 {
3953 if (Byte == ANSI_CHARSET)
3954 {
3955 DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
3956 }
3957 /* We assume SYMBOL_CHARSET for "Marlett" font */
3958 Byte = SYMBOL_CHARSET;
3959 }
3960 }
3961
3962 if (Byte != TM->tmCharSet)
3963 {
3964 if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
3965 {
3966 /* CharSet Penalty 65000 */
3967 /* Requested charset does not match the candidate's. */
3968 Penalty += 65000;
3969 }
3970 else
3971 {
3972 if (UserCharSet != TM->tmCharSet)
3973 {
3974 /* UNDOCUMENTED */
3975 Penalty += 100;
3976 if (ANSI_CHARSET != TM->tmCharSet)
3977 {
3978 /* UNDOCUMENTED */
3979 Penalty += 100;
3980 }
3981 }
3982 }
3983 }
3984 }
3985
3986 Byte = LogFont->lfOutPrecision;
3987 if (Byte == OUT_DEFAULT_PRECIS)
3988 Byte = OUT_OUTLINE_PRECIS; /* Is it OK? */
3989 switch (Byte)
3990 {
3991 case OUT_DEVICE_PRECIS:
3992 if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
3993 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
3994 {
3995 /* OutputPrecision Penalty 19000 */
3996 /* Requested OUT_STROKE_PRECIS, but the device can't do it
3997 or the candidate is not a vector font. */
3998 Penalty += 19000;
3999 }
4000 break;
4001 default:
4002 if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
4003 {
4004 /* OutputPrecision Penalty 19000 */
4005 /* Or OUT_STROKE_PRECIS not requested, and the candidate
4006 is a vector font that requires GDI support. */
4007 Penalty += 19000;
4008 }
4009 break;
4010 }
4011
4012 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4013 if (Byte == DEFAULT_PITCH)
4014 Byte = VARIABLE_PITCH;
4015 if (fFixedSys)
4016 {
4017 /* "FixedSys" font should be fixed-pitch */
4018 Byte = FIXED_PITCH;
4019 }
4020 if (Byte == FIXED_PITCH)
4021 {
4022 if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
4023 {
4024 /* FixedPitch Penalty 15000 */
4025 /* Requested a fixed pitch font, but the candidate is a
4026 variable pitch font. */
4027 Penalty += 15000;
4028 }
4029 }
4030 if (Byte == VARIABLE_PITCH)
4031 {
4032 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4033 {
4034 /* PitchVariable Penalty 350 */
4035 /* Requested a variable pitch font, but the candidate is not a
4036 variable pitch font. */
4037 Penalty += 350;
4038 }
4039 }
4040
4041 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4042 if (Byte == DEFAULT_PITCH)
4043 {
4044 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4045 {
4046 /* DefaultPitchFixed Penalty 1 */
4047 /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
4048 Penalty += 1;
4049 }
4050 }
4051
4052 if (RequestedNameW->Buffer[0])
4053 {
4054 if (RtlEqualUnicodeString(RequestedNameW, FullFaceNameW, TRUE))
4055 {
4056 /* matched with full face name */
4057 }
4058 else if (RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE))
4059 {
4060 /* matched with actual name */
4061 }
4062 else
4063 {
4064 /* try the localized name */
4065 UNICODE_STRING LocalNameW;
4066 FT_Face Face = FontGDI->SharedFace->Face;
4067 IntGetFontLocalizedName(&LocalNameW, Face);
4068 if (RtlEqualUnicodeString(RequestedNameW, &LocalNameW, TRUE))
4069 {
4070 /* matched with localizied name */
4071 }
4072 else
4073 {
4074 /* FaceName Penalty 10000 */
4075 /* Requested a face name, but the candidate's face name
4076 does not match. */
4077 Penalty += 10000;
4078 }
4079 RtlFreeUnicodeString(&LocalNameW);
4080 }
4081 }
4082
4083 Byte = (LogFont->lfPitchAndFamily & 0xF0);
4084 if (Byte != FF_DONTCARE)
4085 {
4086 if (Byte != (TM->tmPitchAndFamily & 0xF0))
4087 {
4088 /* Family Penalty 9000 */
4089 /* Requested a family, but the candidate's family is different. */
4090 Penalty += 9000;
4091 }
4092 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
4093 {
4094 /* FamilyUnknown Penalty 8000 */
4095 /* Requested a family, but the candidate has no family. */
4096 Penalty += 8000;
4097 }
4098 }
4099
4100 /* Is the candidate a non-vector font? */
4101 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4102 {
4103 /* Is lfHeight specified? */
4104 if (LogFont->lfHeight != 0)
4105 {
4106 if (labs(LogFont->lfHeight) < TM->tmHeight)
4107 {
4108 /* HeightBigger Penalty 600 */
4109 /* The candidate is a nonvector font and is bigger than the
4110 requested height. */
4111 Penalty += 600;
4112 /* HeightBiggerDifference Penalty 150 */
4113 /* The candidate is a raster font and is larger than the
4114 requested height. Penalty * height difference */
4115 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4116
4117 fNeedScaling = TRUE;
4118 }
4119 if (TM->tmHeight < labs(LogFont->lfHeight))
4120 {
4121 /* HeightSmaller Penalty 150 */
4122 /* The candidate is a raster font and is smaller than the
4123 requested height. Penalty * height difference */
4124 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4125
4126 fNeedScaling = TRUE;
4127 }
4128 }
4129 }
4130
4131 switch (LogFont->lfPitchAndFamily & 0xF0)
4132 {
4133 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4134 switch (TM->tmPitchAndFamily & 0xF0)
4135 {
4136 case FF_DECORATIVE: case FF_SCRIPT:
4137 /* FamilyUnlikely Penalty 50 */
4138 /* Requested a roman/modern/swiss family, but the
4139 candidate is decorative/script. */
4140 Penalty += 50;
4141 break;
4142 default:
4143 break;
4144 }
4145 break;
4146 case FF_DECORATIVE: case FF_SCRIPT:
4147 switch (TM->tmPitchAndFamily & 0xF0)
4148 {
4149 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4150 /* FamilyUnlikely Penalty 50 */
4151 /* Or requested decorative/script, and the candidate is
4152 roman/modern/swiss. */
4153 Penalty += 50;
4154 break;
4155 default:
4156 break;
4157 }
4158 default:
4159 break;
4160 }
4161
4162 if (LogFont->lfWidth != 0)
4163 {
4164 if (LogFont->lfWidth != TM->tmAveCharWidth)
4165 {
4166 /* Width Penalty 50 */
4167 /* Requested a nonzero width, but the candidate's width
4168 doesn't match. Penalty * width difference */
4169 Penalty += 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth);
4170
4171 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4172 fNeedScaling = TRUE;
4173 }
4174 }
4175
4176 if (fNeedScaling)
4177 {
4178 /* SizeSynth Penalty 50 */
4179 /* The candidate is a raster font that needs scaling by GDI. */
4180 Penalty += 50;
4181 }
4182
4183 if (!!LogFont->lfItalic != !!TM->tmItalic)
4184 {
4185 if (!LogFont->lfItalic && ItalicFromStyle(style_name))
4186 {
4187 /* Italic Penalty 4 */
4188 /* Requested font and candidate font do not agree on italic status,
4189 and the desired result cannot be simulated. */
4190 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
4191 Penalty += 40;
4192 }
4193 else if (LogFont->lfItalic && !ItalicFromStyle(style_name))
4194 {
4195 /* ItalicSim Penalty 1 */
4196 /* Requested italic font but the candidate is not italic,
4197 although italics can be simulated. */
4198 Penalty += 1;
4199 }
4200 }
4201
4202 if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
4203 {
4204 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
4205 {
4206 /* NotTrueType Penalty 4 */
4207 /* Requested OUT_TT_PRECIS, but the candidate is not a
4208 TrueType font. */
4209 Penalty += 4;
4210 }
4211 }
4212
4213 Long = LogFont->lfWeight;
4214 if (LogFont->lfWeight == FW_DONTCARE)
4215 Long = FW_NORMAL;
4216 if (Long != TM->tmWeight)
4217 {
4218 /* Weight Penalty 3 */
4219 /* The candidate's weight does not match the requested weight.
4220 Penalty * (weight difference/10) */
4221 Penalty += 3 * (labs(Long - TM->tmWeight) / 10);
4222 }
4223
4224 if (!LogFont->lfUnderline && TM->tmUnderlined)
4225 {
4226 /* Underline Penalty 3 */
4227 /* Requested font has no underline, but the candidate is
4228 underlined. */
4229 Penalty += 3;
4230 }
4231
4232 if (!LogFont->lfStrikeOut && TM->tmStruckOut)
4233 {
4234 /* StrikeOut Penalty 3 */
4235 /* Requested font has no strike-out, but the candidate is
4236 struck out. */
4237 Penalty += 3;
4238 }
4239
4240 /* Is the candidate a non-vector font? */
4241 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4242 {
4243 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
4244 {
4245 /* VectorHeightSmaller Penalty 2 */
4246 /* Candidate is a vector font that is smaller than the
4247 requested height. Penalty * height difference */
4248 Penalty += 2 * labs(TM->tmHeight - LogFont->lfHeight);
4249 }
4250 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
4251 {
4252 /* VectorHeightBigger Penalty 1 */
4253 /* Candidate is a vector font that is bigger than the
4254 requested height. Penalty * height difference */
4255 Penalty += 1 * labs(TM->tmHeight - LogFont->lfHeight);
4256 }
4257 }
4258
4259 if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
4260 {
4261 /* DeviceFavor Penalty 2 */
4262 /* Extra penalty for all nondevice fonts. */
4263 Penalty += 2;
4264 }
4265
4266 if (Penalty < 200)
4267 {
4268 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
4269 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
4270 "tmCharSet:%d, tmWeight:%ld\n",
4271 Penalty, RequestedNameW->Buffer, ActualNameW->Buffer,
4272 LogFont->lfCharSet, LogFont->lfWeight,
4273 TM->tmCharSet, TM->tmWeight);
4274 }
4275
4276 return Penalty; /* success */
4277 }
4278
4279 static __inline VOID
4280 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, LOGFONTW *LogFont,
4281 PUNICODE_STRING pRequestedNameW,
4282 PUNICODE_STRING pActualNameW, BYTE RequestedCharSet,
4283 PLIST_ENTRY Head)
4284 {
4285 ULONG Penalty;
4286 NTSTATUS Status;
4287 PLIST_ENTRY Entry;
4288 PFONT_ENTRY CurrentEntry;
4289 FONTGDI *FontGDI;
4290 ANSI_STRING ActualNameA;
4291 UNICODE_STRING ActualNameW, FullFaceNameW;
4292 OUTLINETEXTMETRICW *Otm = NULL;
4293 UINT OtmSize, OldOtmSize = 0;
4294 TEXTMETRICW *TM;
4295 FT_Face Face;
4296 LPBYTE pb;
4297
4298 ASSERT(FontObj);
4299 ASSERT(MatchPenalty);
4300 ASSERT(LogFont);
4301 ASSERT(pRequestedNameW);
4302 ASSERT(Head);
4303
4304 /* get the FontObj of lowest penalty */
4305 Entry = Head->Flink;
4306 while (Entry != Head)
4307 {
4308 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
4309 FontGDI = CurrentEntry->Font;
4310 ASSERT(FontGDI);
4311 Face = FontGDI->SharedFace->Face;
4312
4313 /* create actual name */
4314 RtlInitAnsiString(&ActualNameA, Face->family_name);
4315 Status = RtlAnsiStringToUnicodeString(&ActualNameW, &ActualNameA, TRUE);
4316 if (!NT_SUCCESS(Status))
4317 {
4318 /* next entry */
4319 Entry = Entry->Flink;
4320 continue;
4321 }
4322
4323 /* get text metrics */
4324 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4325 if (OtmSize > OldOtmSize)
4326 {
4327 if (Otm)
4328 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4329 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
4330 }
4331
4332 /* update FontObj if lowest penalty */
4333 if (Otm)
4334 {
4335 IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
4336 TM = &Otm->otmTextMetrics;
4337 OldOtmSize = OtmSize;
4338
4339 /* create full name */
4340 pb = (LPBYTE)Otm + (WORD)(DWORD_PTR)Otm->otmpFullName;
4341 Status = RtlCreateUnicodeString(&FullFaceNameW, (LPWSTR)pb);
4342 if (!NT_SUCCESS(Status))
4343 {
4344 RtlFreeUnicodeString(&ActualNameW);
4345 RtlFreeUnicodeString(&FullFaceNameW);
4346 /* next entry */
4347 Entry = Entry->Flink;
4348 continue;
4349 }
4350
4351 Penalty = GetFontPenalty(LogFont, pRequestedNameW, &ActualNameW,
4352 &FullFaceNameW, RequestedCharSet,
4353 FontGDI, Otm, TM, Face->style_name);
4354 if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
4355 {
4356 DPRINT("%ls Penalty: %lu\n", FullFaceNameW.Buffer, Penalty);
4357 RtlFreeUnicodeString(pActualNameW);
4358 RtlCreateUnicodeString(pActualNameW, ActualNameW.Buffer);
4359
4360 *FontObj = GDIToObj(FontGDI, FONT);
4361 *MatchPenalty = Penalty;
4362 }
4363
4364 RtlFreeUnicodeString(&FullFaceNameW);
4365 }
4366
4367 /* free strings */
4368 RtlFreeUnicodeString(&ActualNameW);
4369
4370 /* next entry */
4371 Entry = Entry->Flink;
4372 }
4373
4374 if (Otm)
4375 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4376 }
4377
4378 static
4379 VOID
4380 FASTCALL
4381 IntFontType(PFONTGDI Font)
4382 {
4383 PS_FontInfoRec psfInfo;
4384 FT_ULong tmp_size = 0;
4385 FT_Face Face = Font->SharedFace->Face;
4386
4387 if (FT_HAS_MULTIPLE_MASTERS(Face))
4388 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
4389 if (FT_HAS_VERTICAL(Face))
4390 Font->FontObj.flFontType |= FO_VERT_FACE;
4391 if (!FT_IS_SCALABLE(Face))
4392 Font->FontObj.flFontType |= FO_TYPE_RASTER;
4393 if (FT_IS_SFNT(Face))
4394 {
4395 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
4396 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
4397 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4398 }
4399 if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
4400 {
4401 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4402 }
4403 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
4404 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
4405 {
4406 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
4407 }
4408 }
4409
4410 NTSTATUS
4411 FASTCALL
4412 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
4413 {
4414 NTSTATUS Status = STATUS_SUCCESS;
4415 PTEXTOBJ TextObj;
4416 UNICODE_STRING ActualNameW, RequestedNameW;
4417 PPROCESSINFO Win32Process;
4418 ULONG MatchPenalty;
4419 LOGFONTW *pLogFont;
4420 FT_Face Face;
4421 BYTE RequestedCharSet;
4422
4423 if (!pTextObj)
4424 {
4425 TextObj = TEXTOBJ_LockText(FontHandle);
4426 if (NULL == TextObj)
4427 {
4428 return STATUS_INVALID_HANDLE;
4429 }
4430
4431 if (TextObj->fl & TEXTOBJECT_INIT)
4432 {
4433 TEXTOBJ_UnlockText(TextObj);
4434 return STATUS_SUCCESS;
4435 }
4436 }
4437 else
4438 {
4439 TextObj = pTextObj;
4440 }
4441
4442 RtlInitUnicodeString(&ActualNameW, NULL);
4443
4444 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4445 if (!RtlCreateUnicodeString(&RequestedNameW, pLogFont->lfFaceName))
4446 {
4447 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
4448 return STATUS_NO_MEMORY;
4449 }
4450
4451 /* substitute */
4452 RequestedCharSet = pLogFont->lfCharSet;
4453 DPRINT("Font '%ls,%u' is substituted by: ",
4454 RequestedNameW.Buffer, RequestedCharSet);
4455 SubstituteFontRecurse(&RequestedNameW, &RequestedCharSet);
4456 DPRINT("'%ls,%u'.\n", RequestedNameW.Buffer, RequestedCharSet);
4457
4458 MatchPenalty = 0xFFFFFFFF;
4459 TextObj->Font = NULL;
4460
4461 Win32Process = PsGetCurrentProcessWin32Process();
4462
4463 /* Search private fonts */
4464 IntLockProcessPrivateFonts(Win32Process);
4465 FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont,
4466 &RequestedNameW, &ActualNameW, RequestedCharSet,
4467 &Win32Process->PrivateFontListHead);
4468 IntUnLockProcessPrivateFonts(Win32Process);
4469
4470 /* Search system fonts */
4471 IntLockGlobalFonts;
4472 FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont,
4473 &RequestedNameW, &ActualNameW, RequestedCharSet,
4474 &FontListHead);
4475 IntUnLockGlobalFonts;
4476
4477 if (NULL == TextObj->Font)
4478 {
4479 DPRINT1("Request font %S not found, no fonts loaded at all\n",
4480 pLogFont->lfFaceName);
4481 Status = STATUS_NOT_FOUND;
4482 }
4483 else
4484 {
4485 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
4486 // Need hdev, when freetype is loaded need to create DEVOBJ for
4487 // Consumer and Producer.
4488 TextObj->Font->iUniq = 1; // Now it can be cached.
4489 IntFontType(FontGdi);
4490 FontGdi->flType = TextObj->Font->flFontType;
4491 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
4492 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
4493 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
4494 if (pLogFont->lfWeight != FW_DONTCARE)
4495 FontGdi->RequestWeight = pLogFont->lfWeight;
4496 else
4497 FontGdi->RequestWeight = FW_NORMAL;
4498
4499 Face = FontGdi->SharedFace->Face;
4500
4501 //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name);
4502
4503 if (!FontGdi->OriginalItalic)
4504 FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name);
4505
4506 TextObj->fl |= TEXTOBJECT_INIT;
4507 Status = STATUS_SUCCESS;
4508
4509 DPRINT("RequestedNameW: %ls (CharSet: %d) -> ActualNameW: %ls (CharSet: %d)\n",
4510 RequestedNameW.Buffer, pLogFont->lfCharSet,
4511 ActualNameW.Buffer, FontGdi->CharSet);
4512 }
4513
4514 RtlFreeUnicodeString(&RequestedNameW);
4515 RtlFreeUnicodeString(&ActualNameW);
4516 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
4517
4518 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
4519
4520 return Status;
4521 }
4522
4523
4524 static
4525 BOOL
4526 FASTCALL
4527 IntGetFullFileName(
4528 POBJECT_NAME_INFORMATION NameInfo,
4529 ULONG Size,
4530 PUNICODE_STRING FileName)
4531 {
4532 NTSTATUS Status;
4533 OBJECT_ATTRIBUTES ObjectAttributes;
4534 HANDLE hFile;
4535 IO_STATUS_BLOCK IoStatusBlock;
4536 ULONG Desired;
4537
4538 InitializeObjectAttributes(&ObjectAttributes,
4539 FileName,
4540 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
4541 NULL,
4542 NULL);
4543
4544 Status = ZwOpenFile(
4545 &hFile,
4546 0, // FILE_READ_ATTRIBUTES,
4547 &ObjectAttributes,
4548 &IoStatusBlock,
4549 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4550 0);
4551
4552 if (!NT_SUCCESS(Status))
4553 {
4554 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
4555 return FALSE;
4556 }
4557
4558 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
4559 ZwClose(hFile);
4560 if (!NT_SUCCESS(Status))
4561 {
4562 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
4563 return FALSE;
4564 }
4565
4566 return TRUE;
4567 }
4568
4569 static BOOL
4570 EqualFamilyInfo(FONTFAMILYINFO *pInfo1, FONTFAMILYINFO *pInfo2)
4571 {
4572 UNICODE_STRING Str1, Str2;
4573 ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
4574 ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
4575 RtlInitUnicodeString(&Str1, pLog1->elfLogFont.lfFaceName);
4576 RtlInitUnicodeString(&Str2, pLog2->elfLogFont.lfFaceName);
4577 if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE))
4578 {
4579 return FALSE;
4580 }
4581 if ((pLog1->elfStyle != NULL) != (pLog2->elfStyle != NULL))
4582 return FALSE;
4583 if (pLog1->elfStyle != NULL)
4584 {
4585 RtlInitUnicodeString(&Str1, pLog1->elfStyle);
4586 RtlInitUnicodeString(&Str2, pLog2->elfStyle);
4587 if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE))
4588 {
4589 return FALSE;
4590 }
4591 }
4592 return TRUE;
4593 }
4594
4595 static VOID
4596 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
4597 {
4598 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
4599 if (FamInfo->EnumLogFontEx.elfStyle[0] &&
4600 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
4601 {
4602 wcscat(psz, L" ");
4603 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
4604 }
4605 }
4606
4607 BOOL
4608 FASTCALL
4609 IntGdiGetFontResourceInfo(
4610 PUNICODE_STRING FileName,
4611 PVOID pBuffer,
4612 DWORD *pdwBytes,
4613 DWORD dwType)
4614 {
4615 UNICODE_STRING EntryFileName;
4616 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
4617 PLIST_ENTRY ListEntry;
4618 PFONT_ENTRY FontEntry;
4619 ULONG Size, i, Count;
4620 LPBYTE pbBuffer;
4621 BOOL IsEqual;
4622 FONTFAMILYINFO *FamInfo;
4623 const ULONG MaxFamInfo = 64;
4624 BOOL bSuccess;
4625
4626 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
4627
4628 /* Create buffer for full path name */
4629 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
4630 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4631 if (!NameInfo1)
4632 {
4633 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4634 return FALSE;
4635 }
4636
4637 /* Get the full path name */
4638 if (!IntGetFullFileName(NameInfo1, Size, FileName))
4639 {
4640 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4641 return FALSE;
4642 }
4643
4644 /* Create a buffer for the entries' names */
4645 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4646 if (!NameInfo2)
4647 {
4648 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4649 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4650 return FALSE;
4651 }
4652
4653 FamInfo = ExAllocatePoolWithTag(PagedPool,
4654 sizeof(FONTFAMILYINFO) * MaxFamInfo,
4655 TAG_FINF);
4656 if (!FamInfo)
4657 {
4658 ExFreePoolWithTag(NameInfo2, TAG_FINF);
4659 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4660 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4661 return FALSE;
4662 }
4663 /* Try to find the pathname in the global font list */
4664 Count = 0;
4665 IntLockGlobalFonts;
4666 for (ListEntry = FontListHead.Flink; ListEntry != &FontListHead;
4667 ListEntry = ListEntry->Flink)
4668 {
4669 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
4670 if (FontEntry->Font->Filename == NULL)
4671 continue;
4672
4673 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
4674 if (!IntGetFullFileName(NameInfo2, Size, &EntryFileName))
4675 continue;
4676
4677 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
4678 continue;
4679
4680 IsEqual = FALSE;
4681 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
4682 FontEntry->Font);
4683 for (i = 0; i < Count; ++i)
4684 {
4685 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
4686 {
4687 IsEqual = TRUE;
4688 break;
4689 }
4690 }
4691 if (!IsEqual)
4692 {
4693 /* Found */
4694 ++Count;
4695 if (Count >= MaxFamInfo)
4696 break;
4697 }
4698 }
4699 IntUnLockGlobalFonts;
4700
4701 /* Free the buffers */
4702 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4703 ExFreePool(NameInfo2);
4704
4705 if (Count == 0 && dwType != 5)
4706 {
4707 /* Font could not be found in system table
4708 dwType == 5 will still handle this */
4709 ExFreePoolWithTag(FamInfo, TAG_FINF);
4710 return FALSE;
4711 }
4712
4713 bSuccess = FALSE;
4714 switch (dwType)
4715 {
4716 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
4717 Size = sizeof(DWORD);
4718 if (*pdwBytes == 0)
4719 {
4720 *pdwBytes = Size;
4721 bSuccess = TRUE;
4722 }
4723 else if (pBuffer)
4724 {
4725 if (*pdwBytes >= Size)
4726 {
4727 *(DWORD*)pBuffer = Count;
4728 }
4729 *pdwBytes = Size;
4730 bSuccess = TRUE;
4731 }
4732 break;
4733
4734 case 1: /* copy the font title */
4735 /* calculate the required size */
4736 Size = 0;
4737 Size += wcslen(FamInfo[0].EnumLogFontEx.elfLogFont.lfFaceName);
4738 if (FamInfo[0].EnumLogFontEx.elfStyle[0] &&
4739 _wcsicmp(FamInfo[0].EnumLogFontEx.elfStyle, L"Regular") != 0)
4740 {
4741 Size += 1 + wcslen(FamInfo[0].EnumLogFontEx.elfStyle);
4742 }
4743 for (i = 1; i < Count; ++i)
4744 {
4745 Size += 3; /* " & " */
4746 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
4747 if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
4748 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
4749 {
4750 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
4751 }
4752 }
4753 Size += 2; /* "\0\0" */
4754 Size *= sizeof(WCHAR);
4755
4756 if (*pdwBytes == 0)
4757 {
4758 *pdwBytes = Size;
4759 bSuccess = TRUE;
4760 }
4761 else if (pBuffer)
4762 {
4763 if (*pdwBytes >= Size)
4764 {
4765 /* store font title to buffer */
4766 WCHAR *psz = pBuffer;
4767 *psz = 0;
4768 IntAddNameFromFamInfo(psz, &FamInfo[0]);
4769 for (i = 1; i < Count; ++i)
4770 {
4771 wcscat(psz, L" & ");
4772 IntAddNameFromFamInfo(psz, &FamInfo[i]);
4773 }
4774 psz[wcslen(psz) + 1] = UNICODE_NULL;
4775 *pdwBytes = Size;
4776 bSuccess = TRUE;
4777 }
4778 else
4779 {
4780 *pdwBytes = 1024; /* this is confirmed value */
4781 }
4782 }
4783 break;
4784
4785 case 2: /* Copy an array of LOGFONTW */
4786 Size = Count * sizeof(LOGFONTW);
4787 if (*pdwBytes == 0)
4788 {
4789 *pdwBytes = Size;
4790 bSuccess = TRUE;
4791 }
4792 else if (pBuffer)
4793 {
4794 if (*pdwBytes >= Size)
4795 {
4796 pbBuffer = (LPBYTE)pBuffer;
4797 for (i = 0; i < Count; ++i)
4798 {
4799 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
4800 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
4801 pbBuffer += sizeof(LOGFONTW);
4802 }
4803 }
4804 *pdwBytes = Size;
4805 bSuccess = TRUE;
4806 }
4807 else
4808 {
4809 *pdwBytes = 1024; /* this is confirmed value */
4810 }
4811 break;
4812
4813 case 3:
4814 Size = sizeof(DWORD);
4815 if (*pdwBytes == 0)
4816 {
4817 *pdwBytes = Size;
4818 bSuccess = TRUE;
4819 }
4820 else if (pBuffer)
4821 {
4822 if (*pdwBytes >= Size)
4823 {
4824 /* FIXME: What exactly is copied here? */
4825 *(DWORD*)pBuffer = 1;
4826 }
4827 *pdwBytes = Size;
4828 bSuccess = TRUE;
4829 }
4830 break;
4831
4832 case 4: /* full file path */
4833 if (FileName->Length >= 4 * sizeof(WCHAR))
4834 {
4835 /* The beginning of FileName is \??\ */
4836 LPWSTR pch = FileName->Buffer + 4;
4837 DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
4838
4839 Size = Length + sizeof(WCHAR);
4840 if (*pdwBytes == 0)
4841 {
4842 *pdwBytes = Size;
4843 bSuccess = TRUE;
4844 }
4845 else if (pBuffer)
4846 {
4847 if (*pdwBytes >= Size)
4848 {
4849 RtlCopyMemory(pBuffer, pch, Size);
4850 }
4851 *pdwBytes = Size;
4852 bSuccess = TRUE;
4853 }
4854 }
4855 break;
4856
4857 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
4858 Size = sizeof(BOOL);
4859 if (*pdwBytes == 0)
4860 {
4861 *pdwBytes = Size;
4862 bSuccess = TRUE;
4863 }
4864 else if (pBuffer)
4865 {
4866 if (*pdwBytes >= Size)
4867 {
4868 *(BOOL*)pBuffer = Count == 0;
4869 }
4870 *pdwBytes = Size;
4871 bSuccess = TRUE;
4872 }
4873 break;
4874 }
4875 ExFreePoolWithTag(FamInfo, TAG_FINF);
4876
4877 return bSuccess;
4878 }
4879
4880
4881 BOOL
4882 FASTCALL
4883 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
4884 {
4885 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
4886 Info->iTechnology = RI_TECH_BITMAP;
4887 else
4888 {
4889 if (FT_IS_SCALABLE(Font->SharedFace->Face))
4890 Info->iTechnology = RI_TECH_SCALABLE;
4891 else
4892 Info->iTechnology = RI_TECH_FIXED;
4893 }
4894 Info->iUniq = Font->FontObj.iUniq;
4895 Info->dwUnknown = -1;
4896 return TRUE;
4897 }
4898
4899
4900 DWORD
4901 FASTCALL
4902 ftGdiGetKerningPairs( PFONTGDI Font,
4903 DWORD cPairs,
4904 LPKERNINGPAIR pKerningPair)
4905 {
4906 DWORD Count = 0;
4907 INT i = 0;
4908 FT_Face face = Font->SharedFace->Face;
4909
4910 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
4911 {
4912 FT_UInt previous_index = 0, glyph_index = 0;
4913 FT_ULong char_code, char_previous;
4914 FT_Vector delta;
4915
4916 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
4917
4918 IntLockFreeType;
4919
4920 while (glyph_index)
4921 {
4922 if (previous_index && glyph_index)
4923 {
4924 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
4925
4926 if (pKerningPair && cPairs)
4927 {
4928 pKerningPair[i].wFirst = char_previous;
4929 pKerningPair[i].wSecond = char_code;
4930 pKerningPair[i].iKernAmount = delta.x;
4931 i++;
4932 if (i == cPairs) break;
4933 }
4934 Count++;
4935 }
4936 previous_index = glyph_index;
4937 char_previous = char_code;
4938 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
4939 }
4940 IntUnLockFreeType;
4941 }
4942 return Count;
4943 }
4944
4945
4946 ///////////////////////////////////////////////////////////////////////////
4947 //
4948 // Functions needing sorting.
4949 //
4950 ///////////////////////////////////////////////////////////////////////////
4951 int APIENTRY
4952 NtGdiGetFontFamilyInfo(HDC Dc,
4953 LPLOGFONTW UnsafeLogFont,
4954 PFONTFAMILYINFO UnsafeInfo,
4955 DWORD Size)
4956 {
4957 NTSTATUS Status;
4958 LOGFONTW LogFont;
4959 PFONTFAMILYINFO Info;
4960 DWORD Count;
4961 PPROCESSINFO Win32Process;
4962
4963 /* Make a safe copy */
4964 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
4965 if (! NT_SUCCESS(Status))
4966 {
4967 EngSetLastError(ERROR_INVALID_PARAMETER);
4968 return -1;
4969 }
4970
4971 /* Allocate space for a safe copy */
4972 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT);
4973 if (NULL == Info)
4974 {
4975 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4976 return -1;
4977 }
4978
4979 /* Enumerate font families in the global list */
4980 IntLockGlobalFonts;
4981 Count = 0;
4982 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
4983 {
4984 IntUnLockGlobalFonts;
4985 ExFreePoolWithTag(Info, GDITAG_TEXT);
4986 return -1;
4987 }
4988 IntUnLockGlobalFonts;
4989
4990 /* Enumerate font families in the process local list */
4991 Win32Process = PsGetCurrentProcessWin32Process();
4992 IntLockProcessPrivateFonts(Win32Process);
4993 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
4994 &Win32Process->PrivateFontListHead))
4995 {
4996 IntUnLockProcessPrivateFonts(Win32Process);
4997 ExFreePoolWithTag(Info, GDITAG_TEXT);
4998 return -1;
4999 }
5000 IntUnLockProcessPrivateFonts(Win32Process);
5001
5002 /* Enumerate font families in the registry */
5003 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
5004 {
5005 ExFreePoolWithTag(Info, GDITAG_TEXT);
5006 return -1;
5007 }
5008
5009 /* Return data to caller */
5010 if (0 != Count)
5011 {
5012 Status = MmCopyToCaller(UnsafeInfo, Info,
5013 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
5014 if (! NT_SUCCESS(Status))
5015 {
5016 ExFreePoolWithTag(Info, GDITAG_TEXT);
5017 EngSetLastError(ERROR_INVALID_PARAMETER);
5018 return -1;
5019 }
5020 }
5021
5022 ExFreePoolWithTag(Info, GDITAG_TEXT);
5023
5024 return Count;
5025 }
5026
5027 FORCEINLINE
5028 LONG
5029 ScaleLong(LONG lValue, PFLOATOBJ pef)
5030 {
5031 FLOATOBJ efTemp;
5032
5033 /* Check if we have scaling different from 1 */
5034 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
5035 {
5036 /* Need to multiply */
5037 FLOATOBJ_SetLong(&efTemp, lValue);
5038 FLOATOBJ_Mul(&efTemp, pef);
5039 lValue = FLOATOBJ_GetLong(&efTemp);
5040 }
5041
5042 return lValue;
5043 }
5044
5045 BOOL
5046 APIENTRY
5047 GreExtTextOutW(
5048 IN HDC hDC,
5049 IN INT XStart,
5050 IN INT YStart,
5051 IN UINT fuOptions,
5052 IN OPTIONAL PRECTL lprc,
5053 IN LPCWSTR String,
5054 IN INT Count,
5055 IN OPTIONAL LPINT Dx,
5056 IN DWORD dwCodePage)
5057 {
5058 /*
5059 * FIXME:
5060 * Call EngTextOut, which does the real work (calling DrvTextOut where
5061 * appropriate)
5062 */
5063
5064 DC *dc;
5065 PDC_ATTR pdcattr;
5066 SURFOBJ *SurfObj;
5067 SURFACE *psurf = NULL;
5068 int error, glyph_index, i;
5069 FT_Face face;
5070 FT_GlyphSlot glyph;
5071 FT_BitmapGlyph realglyph;
5072 LONGLONG TextLeft, RealXStart;
5073 ULONG TextTop, previous, BackgroundLeft;
5074 FT_Bool use_kerning;
5075 RECTL DestRect, MaskRect;
5076 POINTL SourcePoint, BrushOrigin;
5077 HBITMAP HSourceGlyph;
5078 SURFOBJ *SourceGlyphSurf;
5079 SIZEL bitSize;
5080 INT yoff;
5081 FONTOBJ *FontObj;
5082 PFONTGDI FontGDI;
5083 PTEXTOBJ TextObj = NULL;
5084 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
5085 FT_Render_Mode RenderMode;
5086 BOOLEAN Render;
5087 POINT Start;
5088 BOOL DoBreak = FALSE;
5089 USHORT DxShift;
5090 PMATRIX pmxWorldToDevice;
5091 LONG fixAscender, fixDescender;
5092 FLOATOBJ Scale;
5093 LOGFONTW *plf;
5094 BOOL EmuBold, EmuItalic;
5095 int thickness;
5096
5097 // TODO: Write test-cases to exactly match real Windows in different
5098 // bad parameters (e.g. does Windows check the DC or the RECT first?).
5099 dc = DC_LockDc(hDC);
5100 if (!dc)
5101 {
5102 EngSetLastError(ERROR_INVALID_HANDLE);
5103 return FALSE;
5104 }
5105 if (dc->dctype == DC_TYPE_INFO)
5106 {
5107 DC_UnlockDc(dc);
5108 /* Yes, Windows really returns TRUE in this case */
5109 return TRUE;
5110 }
5111
5112 pdcattr = dc->pdcattr;
5113
5114 if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE)
5115 {
5116 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5117 DC_vUpdateBackgroundBrush(dc);
5118 }
5119
5120 /* Check if String is valid */
5121 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
5122 {
5123 EngSetLastError(ERROR_INVALID_PARAMETER);
5124 goto fail;
5125 }
5126
5127 DxShift = fuOptions & ETO_PDY ? 1 : 0;
5128
5129 if (PATH_IsPathOpen(dc->dclevel))
5130 {
5131 if (!PATH_ExtTextOut( dc,
5132 XStart,
5133 YStart,
5134 fuOptions,
5135 (const RECTL *)lprc,
5136 String,
5137 Count,
5138 (const INT *)Dx)) goto fail;
5139 goto good;
5140 }
5141
5142 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
5143 {
5144 IntLPtoDP(dc, (POINT *)lprc, 2);
5145 }
5146
5147 if (pdcattr->lTextAlign & TA_UPDATECP)
5148 {
5149 Start.x = pdcattr->ptlCurrent.x;
5150 Start.y = pdcattr->ptlCurrent.y;
5151 } else {
5152 Start.x = XStart;
5153 Start.y = YStart;
5154 }
5155
5156 IntLPtoDP(dc, &Start, 1);
5157 RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
5158 YStart = Start.y + dc->ptlDCOrig.y;
5159
5160 SourcePoint.x = 0;
5161 SourcePoint.y = 0;
5162 MaskRect.left = 0;
5163 MaskRect.top = 0;
5164 BrushOrigin.x = 0;
5165 BrushOrigin.y = 0;
5166
5167 if (!dc->dclevel.pSurface)
5168 {
5169 goto fail;
5170 }
5171
5172 if ((fuOptions & ETO_OPAQUE) && lprc)
5173 {
5174 DestRect.left = lprc->left;
5175 DestRect.top = lprc->top;
5176 DestRect.right = lprc->right;
5177 DestRect.bottom = lprc->bottom;
5178
5179 DestRect.left += dc->ptlDCOrig.x;
5180 DestRect.top += dc->ptlDCOrig.y;
5181 DestRect.right += dc->ptlDCOrig.x;
5182 DestRect.bottom += dc->ptlDCOrig.y;
5183
5184 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5185 {
5186 IntUpdateBoundsRect(dc, &DestRect);
5187 }
5188
5189 DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL);
5190
5191 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5192 DC_vUpdateBackgroundBrush(dc);
5193
5194 psurf = dc->dclevel.pSurface;
5195 IntEngBitBlt(
5196 &psurf->SurfObj,
5197 NULL,
5198 NULL,
5199 &dc->co.ClipObj,
5200 NULL,
5201 &DestRect,
5202 &SourcePoint,
5203 &SourcePoint,
5204 &dc->eboBackground.BrushObject,
5205 &BrushOrigin,
5206 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5207 fuOptions &= ~ETO_OPAQUE;
5208 DC_vFinishBlit(dc, NULL);
5209 }
5210 else
5211 {
5212 if (pdcattr->jBkMode == OPAQUE)
5213 {
5214 fuOptions |= ETO_OPAQUE;
5215 }
5216 }
5217
5218 TextObj = RealizeFontInit(pdcattr->hlfntNew);
5219 if (TextObj == NULL)
5220 {
5221 goto fail;
5222 }
5223
5224 FontObj = TextObj->Font;
5225 ASSERT(FontObj);
5226 FontGDI = ObjToGDI(FontObj, FONT);
5227 ASSERT(FontGDI);
5228
5229 IntLockFreeType;
5230 face = FontGDI->SharedFace->Face;
5231
5232 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5233 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
5234 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
5235
5236 Render = IntIsFontRenderingEnabled();
5237 if (Render)
5238 RenderMode = IntGetFontRenderMode(plf);
5239 else
5240 RenderMode = FT_RENDER_MODE_MONO;
5241
5242 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
5243 {
5244 IntUnLockFreeType;
5245 goto fail;
5246 }
5247
5248 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
5249 {
5250 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
5251 FtSetCoordinateTransform(face, pmxWorldToDevice);
5252
5253 fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
5254 fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
5255 }
5256 else
5257 {
5258 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
5259 FtSetCoordinateTransform(face, pmxWorldToDevice);
5260
5261 fixAscender = face->size->metrics.ascender;
5262 fixDescender = face->size->metrics.descender;
5263 }
5264
5265 /*
5266 * Process the vertical alignment and determine the yoff.
5267 */
5268
5269 if (pdcattr->lTextAlign & TA_BASELINE)
5270 yoff = 0;
5271 else if (pdcattr->lTextAlign & TA_BOTTOM)
5272 yoff = -fixDescender >> 6;
5273 else /* TA_TOP */
5274 yoff = fixAscender >> 6;
5275
5276 use_kerning = FT_HAS_KERNING(face);
5277 previous = 0;
5278
5279 /*
5280 * Process the horizontal alignment and modify XStart accordingly.
5281 */
5282
5283 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
5284 {
5285 ULONGLONG TextWidth = 0;
5286 LPCWSTR TempText = String;
5287 int iStart;
5288
5289 /*
5290 * Calculate width of the text.
5291 */
5292
5293 if (NULL != Dx)
5294 {
5295 iStart = Count < 2 ? 0 : Count - 2;
5296 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
5297 }
5298 else
5299 {
5300 iStart = 0;
5301 }
5302 TempText = String + iStart;
5303
5304 for (i = iStart; i < Count; i++)
5305 {
5306 if (fuOptions & ETO_GLYPH_INDEX)
5307 glyph_index = *TempText;
5308 else
5309 glyph_index = FT_Get_Char_Index(face, *TempText);
5310
5311 if (EmuBold || EmuItalic)
5312 realglyph = NULL;
5313 else
5314 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
5315 plf->lfHeight, pmxWorldToDevice);
5316 if (!realglyph)
5317 {
5318 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5319 if (error)
5320 {
5321 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
5322 }
5323
5324 glyph = face->glyph;
5325 if (EmuBold || EmuItalic)
5326 {
5327 if (EmuBold)
5328 FT_GlyphSlot_Embolden(glyph);
5329 if (EmuItalic)
5330 FT_GlyphSlot_Oblique(glyph);
5331 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5332 }
5333 else
5334 {
5335 realglyph = ftGdiGlyphCacheSet(face,
5336 glyph_index,
5337 plf->lfHeight,
5338 pmxWorldToDevice,
5339 glyph,
5340 RenderMode);
5341 }
5342 if (!realglyph)
5343 {
5344 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5345 IntUnLockFreeType;
5346 goto fail;
5347 }
5348
5349 }
5350 /* Retrieve kerning distance */
5351 if (use_kerning && previous && glyph_index)
5352 {
5353 FT_Vector delta;
5354 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5355 TextWidth += delta.x;
5356 }
5357
5358 TextWidth += realglyph->root.advance.x >> 10;
5359
5360 if (EmuBold || EmuItalic)
5361 {
5362 FT_Done_Glyph((FT_Glyph)realglyph);
5363 realglyph = NULL;
5364 }
5365
5366 previous = glyph_index;
5367 TempText++;
5368 }
5369
5370 previous = 0;
5371
5372 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
5373 {
5374 RealXStart -= TextWidth / 2;
5375 }
5376 else
5377 {
5378 RealXStart -= TextWidth;
5379 }
5380 }
5381
5382 /* Lock blit with a dummy rect */
5383 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
5384
5385 psurf = dc->dclevel.pSurface;
5386 SurfObj = &psurf->SurfObj ;
5387
5388 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
5389 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
5390
5391 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
5392 DC_vUpdateBackgroundBrush(dc) ;
5393
5394 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
5395 DC_vUpdateTextBrush(dc) ;
5396
5397 if (!face->units_per_EM)
5398 {
5399 thickness = 1;
5400 }
5401 else
5402 {
5403 thickness = face->underline_thickness *
5404 face->size->metrics.y_ppem / face->units_per_EM;
5405 if (thickness <= 0)
5406 thickness = 1;
5407 }
5408
5409 if ((fuOptions & ETO_OPAQUE) && plf->lfItalic)
5410 {
5411 /* Draw background */
5412 TextLeft = RealXStart;
5413 TextTop = YStart;
5414 BackgroundLeft = (RealXStart + 32) >> 6;
5415 for (i = 0; i < Count; ++i)
5416 {
5417 if (fuOptions & ETO_GLYPH_INDEX)
5418 glyph_index = String[i];
5419 else
5420 glyph_index = FT_Get_Char_Index(face, String[i]);
5421
5422 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5423 if (error)
5424 {
5425 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5426 IntUnLockFreeType;
5427 DC_vFinishBlit(dc, NULL);
5428 goto fail2;
5429 }
5430
5431 glyph = face->glyph;
5432 if (EmuBold)
5433 FT_GlyphSlot_Embolden(glyph);
5434 if (EmuItalic)
5435 FT_GlyphSlot_Oblique(glyph);
5436 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5437 if (!realglyph)
5438 {
5439 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5440 IntUnLockFreeType;
5441 DC_vFinishBlit(dc, NULL);
5442 goto fail2;
5443 }
5444
5445 /* retrieve kerning distance and move pen position */
5446 if (use_kerning && previous && glyph_index && NULL == Dx)
5447 {
5448 FT_Vector delta;
5449 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5450 TextLeft += delta.x;
5451 }
5452 DPRINT("TextLeft: %I64d\n", TextLeft);
5453 DPRINT("TextTop: %lu\n", TextTop);
5454 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5455
5456 DestRect.left = BackgroundLeft;
5457 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5458 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5459 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5460 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5461 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5462 {
5463 IntUpdateBoundsRect(dc, &DestRect);
5464 }
5465 IntEngBitBlt(
5466 &psurf->SurfObj,
5467 NULL,
5468 NULL,
5469 &dc->co.ClipObj,
5470 NULL,
5471 &DestRect,
5472 &SourcePoint,
5473 &SourcePoint,
5474 &dc->eboBackground.BrushObject,
5475 &BrushOrigin,
5476 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5477 MouseSafetyOnDrawEnd(dc->ppdev);
5478 BackgroundLeft = DestRect.right;
5479
5480 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5481 DestRect.right = DestRect.left + realglyph->bitmap.width;
5482 DestRect.top = TextTop + yoff - realglyph->top;
5483 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5484
5485 bitSize.cx = realglyph->bitmap.width;
5486 bitSize.cy = realglyph->bitmap.rows;
5487 MaskRect.right = realglyph->bitmap.width;
5488 MaskRect.bottom = realglyph->bitmap.rows;
5489
5490 if (NULL == Dx)
5491 {
5492 TextLeft += realglyph->root.advance.x >> 10;
5493 DPRINT("New TextLeft: %I64d\n", TextLeft);
5494 }
5495 else
5496 {
5497 // FIXME this should probably be a matrix transform with TextTop as well.
5498 Scale = pdcattr->mxWorldToDevice.efM11;
5499 if (FLOATOBJ_Equal0(&Scale))
5500 FLOATOBJ_Set1(&Scale);
5501
5502 /* do the shift before multiplying to preserve precision */
5503 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5504 TextLeft += FLOATOBJ_GetLong(&Scale);
5505 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5506 }
5507
5508 if (DxShift)
5509 {
5510 TextTop -= Dx[2 * i + 1] << 6;
5511 }
5512
5513 previous = glyph_index;
5514
5515 if (EmuBold || EmuItalic)
5516 {
5517 FT_Done_Glyph((FT_Glyph)realglyph);
5518 realglyph = NULL;
5519 }
5520 }
5521 }
5522
5523 /*
5524 * The main rendering loop.
5525 */
5526 TextLeft = RealXStart;
5527 TextTop = YStart;
5528 BackgroundLeft = (RealXStart + 32) >> 6;
5529 for (i = 0; i < Count; ++i)
5530 {
5531 if (fuOptions & ETO_GLYPH_INDEX)
5532 glyph_index = String[i];
5533 else
5534 glyph_index = FT_Get_Char_Index(face, String[i]);
5535
5536 if (EmuBold || EmuItalic)
5537 realglyph = NULL;
5538 else
5539 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
5540 plf->lfHeight, pmxWorldToDevice);
5541 if (!realglyph)
5542 {
5543 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5544 if (error)
5545 {
5546 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5547 IntUnLockFreeType;
5548 DC_vFinishBlit(dc, NULL);
5549 goto fail2;
5550 }
5551
5552 glyph = face->glyph;
5553 if (EmuBold || EmuItalic)
5554 {
5555 if (EmuBold)
5556 FT_GlyphSlot_Embolden(glyph);
5557 if (EmuItalic)
5558 FT_GlyphSlot_Oblique(glyph);
5559 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5560 }
5561 else
5562 {
5563 realglyph = ftGdiGlyphCacheSet(face,
5564 glyph_index,
5565 plf->lfHeight,
5566 pmxWorldToDevice,
5567 glyph,
5568 RenderMode);
5569 }
5570 if (!realglyph)
5571 {
5572 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5573 IntUnLockFreeType;
5574 DC_vFinishBlit(dc, NULL);
5575 goto fail2;
5576 }
5577 }
5578
5579 /* retrieve kerning distance and move pen position */
5580 if (use_kerning && previous && glyph_index && NULL == Dx)
5581 {
5582 FT_Vector delta;
5583 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5584 TextLeft += delta.x;
5585 }
5586 DPRINT("TextLeft: %I64d\n", TextLeft);
5587 DPRINT("TextTop: %lu\n", TextTop);
5588 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5589
5590 if ((fuOptions & ETO_OPAQUE) && !plf->lfItalic)
5591 {
5592 DestRect.left = BackgroundLeft;
5593 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5594 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5595 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5596 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5597 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5598 {
5599 IntUpdateBoundsRect(dc, &DestRect);
5600 }
5601 IntEngBitBlt(
5602 &psurf->SurfObj,
5603 NULL,
5604 NULL,
5605 &dc->co.ClipObj,
5606 NULL,
5607 &DestRect,
5608 &SourcePoint,
5609 &SourcePoint,
5610 &dc->eboBackground.BrushObject,
5611 &BrushOrigin,
5612 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5613 MouseSafetyOnDrawEnd(dc->ppdev);
5614 BackgroundLeft = DestRect.right;
5615 }
5616
5617 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5618 DestRect.right = DestRect.left + realglyph->bitmap.width;
5619 DestRect.top = TextTop + yoff - realglyph->top;
5620 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5621
5622 bitSize.cx = realglyph->bitmap.width;
5623 bitSize.cy = realglyph->bitmap.rows;
5624 MaskRect.right = realglyph->bitmap.width;
5625 MaskRect.bottom = realglyph->bitmap.rows;
5626
5627 /* Check if the bitmap has any pixels */
5628 if ((bitSize.cx != 0) && (bitSize.cy != 0))
5629 {
5630 /*
5631 * We should create the bitmap out of the loop at the biggest possible
5632 * glyph size. Then use memset with 0 to clear it and sourcerect to
5633 * limit the work of the transbitblt.
5634 */
5635 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
5636 BMF_8BPP, BMF_TOPDOWN,
5637 realglyph->bitmap.buffer);
5638 if ( !HSourceGlyph )
5639 {
5640 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
5641 // FT_Done_Glyph(realglyph);
5642 IntUnLockFreeType;
5643 DC_vFinishBlit(dc, NULL);
5644 goto fail2;
5645 }
5646 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
5647 if ( !SourceGlyphSurf )
5648 {
5649 EngDeleteSurface((HSURF)HSourceGlyph);
5650 DPRINT1("WARNING: EngLockSurface() failed!\n");
5651 IntUnLockFreeType;
5652 DC_vFinishBlit(dc, NULL);
5653 goto fail2;
5654 }
5655
5656 /*
5657 * Use the font data as a mask to paint onto the DCs surface using a
5658 * brush.
5659 */
5660 if (lprc && (fuOptions & ETO_CLIPPED) &&
5661 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
5662 {
5663 // We do the check '>=' instead of '>' to possibly save an iteration
5664 // through this loop, since it's breaking after the drawing is done,
5665 // and x is always incremented.
5666 DestRect.right = lprc->right + dc->ptlDCOrig.x;
5667 DoBreak = TRUE;
5668 }
5669 if (lprc && (fuOptions & ETO_CLIPPED) &&
5670 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
5671 {
5672 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
5673 }
5674 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5675 if (!IntEngMaskBlt(
5676 SurfObj,
5677 SourceGlyphSurf,
5678 &dc->co.ClipObj,
5679 &exloRGB2Dst.xlo,
5680 &exloDst2RGB.xlo,
5681 &DestRect,
5682 (PPOINTL)&MaskRect,
5683 &dc->eboText.BrushObject,
5684 &BrushOrigin))
5685 {
5686 DPRINT1("Failed to MaskBlt a glyph!\n");
5687 }
5688
5689 MouseSafetyOnDrawEnd(dc->ppdev) ;
5690
5691 EngUnlockSurface(SourceGlyphSurf);
5692 EngDeleteSurface((HSURF)HSourceGlyph);
5693 }
5694
5695 if (DoBreak)
5696 {
5697 break;
5698 }
5699
5700 if (plf->lfUnderline)
5701 {
5702 int i, position;
5703 if (!face->units_per_EM)
5704 {
5705 position = 0;
5706 }
5707 else
5708 {
5709 position = face->underline_position *
5710 face->size->metrics.y_ppem / face->units_per_EM;
5711 }
5712 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5713 {
5714 EngLineTo(SurfObj,
5715 &dc->co.ClipObj,
5716 &dc->eboText.BrushObject,
5717 (TextLeft >> 6),
5718 TextTop + yoff - position + i,
5719 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5720 TextTop + yoff - position + i,
5721 NULL,
5722 ROP2_TO_MIX(R2_COPYPEN));
5723 }
5724 }
5725 if (plf->lfStrikeOut)
5726 {
5727 int i;
5728 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5729 {
5730 EngLineTo(SurfObj,
5731 &dc->co.ClipObj,
5732 &dc->eboText.BrushObject,
5733 (TextLeft >> 6),
5734 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5735 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5736 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5737 NULL,
5738 ROP2_TO_MIX(R2_COPYPEN));
5739 }
5740 }
5741
5742 if (NULL == Dx)
5743 {
5744 TextLeft += realglyph->root.advance.x >> 10;
5745 DPRINT("New TextLeft: %I64d\n", TextLeft);
5746 }
5747 else
5748 {
5749 // FIXME this should probably be a matrix transform with TextTop as well.
5750 Scale = pdcattr->mxWorldToDevice.efM11;
5751 if (FLOATOBJ_Equal0(&Scale))
5752 FLOATOBJ_Set1(&Scale);
5753
5754 /* do the shift before multiplying to preserve precision */
5755 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5756 TextLeft += FLOATOBJ_GetLong(&Scale);
5757 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5758 }
5759
5760 if (DxShift)
5761 {
5762 TextTop -= Dx[2 * i + 1] << 6;
5763 }
5764
5765 previous = glyph_index;
5766
5767 if (EmuBold || EmuItalic)
5768 {
5769 FT_Done_Glyph((FT_Glyph)realglyph);
5770 realglyph = NULL;
5771 }
5772 }
5773
5774 if (pdcattr->lTextAlign & TA_UPDATECP) {
5775 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
5776 }
5777
5778 IntUnLockFreeType;
5779
5780 DC_vFinishBlit(dc, NULL) ;
5781
5782 EXLATEOBJ_vCleanup(&exloRGB2Dst);
5783 EXLATEOBJ_vCleanup(&exloDst2RGB);
5784 if (TextObj != NULL)
5785 TEXTOBJ_UnlockText(TextObj);
5786 good:
5787 DC_UnlockDc( dc );
5788
5789 return TRUE;
5790
5791 fail2:
5792 EXLATEOBJ_vCleanup(&exloRGB2Dst);
5793 EXLATEOBJ_vCleanup(&exloDst2RGB);
5794 fail:
5795 if (TextObj != NULL)
5796 TEXTOBJ_UnlockText(TextObj);
5797
5798 DC_UnlockDc(dc);
5799
5800 return FALSE;
5801 }
5802
5803 #define STACK_TEXT_BUFFER_SIZE 100
5804 BOOL
5805 APIENTRY
5806 NtGdiExtTextOutW(
5807 IN HDC hDC,
5808 IN INT XStart,
5809 IN INT YStart,
5810 IN UINT fuOptions,
5811 IN OPTIONAL LPRECT UnsafeRect,
5812 IN LPWSTR UnsafeString,
5813 IN INT Count,
5814 IN OPTIONAL LPINT UnsafeDx,
5815 IN DWORD dwCodePage)
5816 {
5817 BOOL Result = FALSE;
5818 NTSTATUS Status = STATUS_SUCCESS;
5819 RECTL SafeRect;
5820 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
5821 PVOID Buffer = LocalBuffer;
5822 LPCWSTR SafeString = NULL;
5823 LPINT SafeDx = NULL;
5824 ULONG BufSize, StringSize, DxSize = 0;
5825
5826 /* Check if String is valid */
5827 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
5828 {
5829 EngSetLastError(ERROR_INVALID_PARAMETER);
5830 return FALSE;
5831 }
5832
5833 if (Count > 0)
5834 {
5835 /* Calculate buffer size for string and Dx values */
5836 BufSize = StringSize = Count * sizeof(WCHAR);
5837 if (UnsafeDx)
5838 {
5839 /* If ETO_PDY is specified, we have pairs of INTs */
5840 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
5841 BufSize += DxSize;
5842 }
5843
5844 /* Check if our local buffer is large enough */
5845 if (BufSize > STACK_TEXT_BUFFER_SIZE)
5846 {
5847 /* It's not, allocate a temp buffer */
5848 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
5849 if (!Buffer)
5850 {
5851 return FALSE;
5852 }
5853 }
5854
5855 /* Probe and copy user mode data to the buffer */
5856 _SEH2_TRY
5857 {
5858 /* Put the Dx before the String to assure alignment of 4 */
5859 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
5860
5861 /* Probe and copy the string */
5862 ProbeForRead(UnsafeString, StringSize, 1);
5863 memcpy((PVOID)SafeString, UnsafeString, StringSize);
5864
5865 /* If we have Dx values... */
5866 if (UnsafeDx)
5867 {
5868 /* ... probe and copy them */
5869 SafeDx = Buffer;
5870 ProbeForRead(UnsafeDx, DxSize, 1);
5871 memcpy(SafeDx, UnsafeDx, DxSize);
5872 }
5873 }
5874 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5875 {
5876 Status = _SEH2_GetExceptionCode();
5877 }
5878 _SEH2_END
5879 if (!NT_SUCCESS(Status))
5880 {
5881 goto cleanup;
5882 }
5883 }
5884
5885 /* If we have a rect, copy it */
5886 if (UnsafeRect)
5887 {
5888 _SEH2_TRY
5889 {
5890 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
5891 SafeRect = *UnsafeRect;
5892 }
5893 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5894 {
5895 Status = _SEH2_GetExceptionCode();
5896 }
5897 _SEH2_END
5898 if (!NT_SUCCESS(Status))
5899 {
5900 goto cleanup;
5901 }
5902 }
5903
5904 /* Finally call the internal routine */
5905 Result = GreExtTextOutW(hDC,
5906 XStart,
5907 YStart,
5908 fuOptions,
5909 &SafeRect,
5910 SafeString,
5911 Count,
5912 SafeDx,
5913 dwCodePage);
5914
5915 cleanup:
5916 /* If we allocated a buffer, free it */
5917 if (Buffer != LocalBuffer)
5918 {
5919 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
5920 }
5921
5922 return Result;
5923 }
5924
5925
5926 /*
5927 * @implemented
5928 */
5929 BOOL
5930 APIENTRY
5931 NtGdiGetCharABCWidthsW(
5932 IN HDC hDC,
5933 IN UINT FirstChar,
5934 IN ULONG Count,
5935 IN OPTIONAL PWCHAR UnSafepwch,
5936 IN FLONG fl,
5937 OUT PVOID Buffer)
5938 {
5939 LPABC SafeBuff;
5940 LPABCFLOAT SafeBuffF = NULL;
5941 PDC dc;
5942 PDC_ATTR pdcattr;
5943 PTEXTOBJ TextObj;
5944 PFONTGDI FontGDI;
5945 FT_Face face;
5946 FT_CharMap charmap, found = NULL;
5947 UINT i, glyph_index, BufferSize;
5948 HFONT hFont = 0;
5949 NTSTATUS Status = STATUS_SUCCESS;
5950 PMATRIX pmxWorldToDevice;
5951 PWCHAR Safepwch = NULL;
5952 LOGFONTW *plf;
5953
5954 if (!Buffer)
5955 {
5956 EngSetLastError(ERROR_INVALID_PARAMETER);
5957 return FALSE;
5958 }
5959
5960 if (UnSafepwch)
5961 {
5962 UINT pwchSize = Count * sizeof(WCHAR);
5963 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
5964
5965 if(!Safepwch)
5966 {
5967 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5968 return FALSE;
5969 }
5970
5971 _SEH2_TRY
5972 {
5973 ProbeForRead(UnSafepwch, pwchSize, 1);
5974 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
5975 }
5976 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5977 {
5978 Status = _SEH2_GetExceptionCode();
5979 }
5980 _SEH2_END;
5981 }
5982
5983 if (!NT_SUCCESS(Status))
5984 {
5985 if(Safepwch)
5986 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
5987
5988 EngSetLastError(Status);
5989 return FALSE;
5990 }
5991
5992 BufferSize = Count * sizeof(ABC); // Same size!
5993 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
5994 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
5995 if (SafeBuff == NULL)
5996 {
5997
5998 if(Safepwch)
5999 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6000
6001 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6002 return FALSE;
6003 }
6004
6005 dc = DC_LockDc(hDC);
6006 if (dc == NULL)
6007 {
6008 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6009
6010 if(Safepwch)
6011 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6012
6013 EngSetLastError(ERROR_INVALID_HANDLE);
6014 return FALSE;
6015 }
6016 pdcattr = dc->pdcattr;
6017 hFont = pdcattr->hlfntNew;
6018 TextObj = RealizeFontInit(hFont);
6019
6020 /* Get the DC's world-to-device transformation matrix */
6021 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6022 DC_UnlockDc(dc);
6023
6024 if (TextObj == NULL)
6025 {
6026 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6027
6028 if(Safepwch)
6029 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6030
6031 EngSetLastError(ERROR_INVALID_HANDLE);
6032 return FALSE;
6033 }
6034
6035 FontGDI = ObjToGDI(TextObj->Font, FONT);
6036
6037 face = FontGDI->SharedFace->Face;
6038 if (face->charmap == NULL)
6039 {
6040 for (i = 0; i < (UINT)face->num_charmaps; i++)
6041 {
6042 charmap = face->charmaps[i];
6043 if (charmap->encoding != 0)
6044 {
6045 found = charmap;
6046 break;
6047 }
6048 }
6049
6050 if (!found)
6051 {
6052 DPRINT1("WARNING: Could not find desired charmap!\n");
6053 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6054
6055 if(Safepwch)
6056 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6057
6058 EngSetLastError(ERROR_INVALID_HANDLE);
6059 return FALSE;
6060 }
6061
6062 IntLockFreeType;
6063 FT_Set_Charmap(face, found);
6064 IntUnLockFreeType;
6065 }
6066
6067 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6068 IntLockFreeType;
6069 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
6070 FtSetCoordinateTransform(face, pmxWorldToDevice);
6071
6072 for (i = FirstChar; i < FirstChar+Count; i++)
6073 {
6074 int adv, lsb, bbx, left, right;
6075
6076 if (Safepwch)
6077 {
6078 if (fl & GCABCW_INDICES)
6079 glyph_index = Safepwch[i - FirstChar];
6080 else
6081 glyph_index = FT_Get_Char_Index(face, Safepwch[i - FirstChar]);
6082 }
6083 else
6084 {
6085 if (fl & GCABCW_INDICES)
6086 glyph_index = i;
6087 else
6088 glyph_index = FT_Get_Char_Index(face, i);
6089 }
6090 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6091
6092 left = (INT)face->glyph->metrics.horiBearingX & -64;
6093 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
6094 adv = (face->glyph->advance.x + 32) >> 6;
6095
6096 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
6097 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
6098
6099 lsb = left >> 6;
6100 bbx = (right - left) >> 6;
6101 /*
6102 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
6103 */
6104 if (!fl)
6105 {
6106 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
6107 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
6108 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
6109 }
6110 else
6111 {
6112 SafeBuff[i - FirstChar].abcA = lsb;
6113 SafeBuff[i - FirstChar].abcB = bbx;
6114 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
6115 }
6116 }
6117 IntUnLockFreeType;
6118 TEXTOBJ_UnlockText(TextObj);
6119 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6120
6121 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6122
6123 if(Safepwch)
6124 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6125
6126 if (! NT_SUCCESS(Status))
6127 {
6128 SetLastNtError(Status);
6129 return FALSE;
6130 }
6131
6132 DPRINT("NtGdiGetCharABCWidths Worked!\n");
6133 return TRUE;
6134 }
6135
6136 /*
6137 * @implemented
6138 */
6139 BOOL
6140 APIENTRY
6141 NtGdiGetCharWidthW(
6142 IN HDC hDC,
6143 IN UINT FirstChar,
6144 IN UINT Count,
6145 IN OPTIONAL PWCHAR UnSafepwc,
6146 IN FLONG fl,
6147 OUT PVOID Buffer)
6148 {
6149 NTSTATUS Status = STATUS_SUCCESS;
6150 LPINT SafeBuff;
6151 PFLOAT SafeBuffF = NULL;
6152 PDC dc;
6153 PDC_ATTR pdcattr;
6154 PTEXTOBJ TextObj;
6155 PFONTGDI FontGDI;
6156 FT_Face face;
6157 FT_CharMap charmap, found = NULL;
6158 UINT i, glyph_index, BufferSize;
6159 HFONT hFont = 0;
6160 PMATRIX pmxWorldToDevice;
6161 PWCHAR Safepwc = NULL;
6162 LOGFONTW *plf;
6163
6164 if (UnSafepwc)
6165 {
6166 UINT pwcSize = Count * sizeof(WCHAR);
6167 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6168
6169 if(!Safepwc)
6170 {
6171 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6172 return FALSE;
6173 }
6174 _SEH2_TRY
6175 {
6176 ProbeForRead(UnSafepwc, pwcSize, 1);
6177 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6178 }
6179 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6180 {
6181 Status = _SEH2_GetExceptionCode();
6182 }
6183 _SEH2_END;
6184 }
6185
6186 if (!NT_SUCCESS(Status))
6187 {
6188 EngSetLastError(Status);
6189 return FALSE;
6190 }
6191
6192 BufferSize = Count * sizeof(INT); // Same size!
6193 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6194 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
6195 if (SafeBuff == NULL)
6196 {
6197 if(Safepwc)
6198 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6199
6200 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6201 return FALSE;
6202 }
6203
6204 dc = DC_LockDc(hDC);
6205 if (dc == NULL)
6206 {
6207 if(Safepwc)
6208 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6209
6210 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6211 EngSetLastError(ERROR_INVALID_HANDLE);
6212 return FALSE;
6213 }
6214 pdcattr = dc->pdcattr;
6215 hFont = pdcattr->hlfntNew;
6216 TextObj = RealizeFontInit(hFont);
6217 /* Get the DC's world-to-device transformation matrix */
6218 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6219 DC_UnlockDc(dc);
6220
6221 if (TextObj == NULL)
6222 {
6223 if(Safepwc)
6224 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6225
6226 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6227 EngSetLastError(ERROR_INVALID_HANDLE);
6228 return FALSE;
6229 }
6230
6231 FontGDI = ObjToGDI(TextObj->Font, FONT);
6232
6233 face = FontGDI->SharedFace->Face;
6234 if (face->charmap == NULL)
6235 {
6236 for (i = 0; i < (UINT)face->num_charmaps; i++)
6237 {
6238 charmap = face->charmaps[i];
6239 if (charmap->encoding != 0)
6240 {
6241 found = charmap;
6242 break;
6243 }
6244 }
6245
6246 if (!found)
6247 {
6248 DPRINT1("WARNING: Could not find desired charmap!\n");
6249
6250 if(Safepwc)
6251 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6252
6253 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6254 EngSetLastError(ERROR_INVALID_HANDLE);
6255 return FALSE;
6256 }
6257
6258 IntLockFreeType;
6259 FT_Set_Charmap(face, found);
6260 IntUnLockFreeType;
6261 }
6262
6263 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6264 IntLockFreeType;
6265 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
6266 FtSetCoordinateTransform(face, pmxWorldToDevice);
6267
6268 for (i = FirstChar; i < FirstChar+Count; i++)
6269 {
6270 if (Safepwc)
6271 {
6272 if (fl & GCW_INDICES)
6273 glyph_index = Safepwc[i - FirstChar];
6274 else
6275 glyph_index = FT_Get_Char_Index(face, Safepwc[i - FirstChar]);
6276 }
6277 else
6278 {
6279 if (fl & GCW_INDICES)
6280 glyph_index = i;
6281 else
6282 glyph_index = FT_Get_Char_Index(face, i);
6283 }
6284 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6285 if (!fl)
6286 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
6287 else
6288 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
6289 }
6290 IntUnLockFreeType;
6291 TEXTOBJ_UnlockText(TextObj);
6292 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6293
6294 if(Safepwc)
6295 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6296
6297 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6298 return TRUE;
6299 }
6300
6301
6302 /*
6303 * @implemented
6304 */
6305 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
6306 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
6307 // NOTE: See also GreGetGlyphIndicesW.
6308 __kernel_entry
6309 W32KAPI
6310 DWORD
6311 APIENTRY
6312 NtGdiGetGlyphIndicesW(
6313 _In_ HDC hdc,
6314 _In_reads_opt_(cwc) LPCWSTR pwc,
6315 _In_ INT cwc,
6316 _Out_writes_opt_(cwc) LPWORD pgi,
6317 _In_ DWORD iMode)
6318 {
6319 PDC dc;
6320 PDC_ATTR pdcattr;
6321 PTEXTOBJ TextObj;
6322 PFONTGDI FontGDI;
6323 HFONT hFont = NULL;
6324 NTSTATUS Status = STATUS_SUCCESS;
6325 OUTLINETEXTMETRICW *potm;
6326 INT i;
6327 WCHAR DefChar = 0xffff;
6328 PWSTR Buffer = NULL;
6329 ULONG Size, pwcSize;
6330 PWSTR Safepwc = NULL;
6331 LPCWSTR UnSafepwc = pwc;
6332 LPWORD UnSafepgi = pgi;
6333
6334 /* Check for integer overflow */
6335 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN
6336 return GDI_ERROR;
6337
6338 if (!UnSafepwc && !UnSafepgi)
6339 return cwc;
6340
6341 if (!UnSafepwc || !UnSafepgi)
6342 {
6343 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
6344 return GDI_ERROR;
6345 }
6346
6347 // TODO: Special undocumented case!
6348 if (!pwc && !pgi && (cwc == 0))
6349 {
6350 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n");
6351 return 0;
6352 }
6353
6354 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825
6355 if (cwc == 0)
6356 {
6357 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n");
6358 return GDI_ERROR;
6359 }
6360
6361 dc = DC_LockDc(hdc);
6362 if (!dc)
6363 {
6364 return GDI_ERROR;
6365 }
6366 pdcattr = dc->pdcattr;
6367 hFont = pdcattr->hlfntNew;
6368 TextObj = RealizeFontInit(hFont);
6369 DC_UnlockDc(dc);
6370 if (!TextObj)
6371 {
6372 return GDI_ERROR;
6373 }
6374
6375 FontGDI = ObjToGDI(TextObj->Font, FONT);
6376 TEXTOBJ_UnlockText(TextObj);
6377
6378 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
6379 if (!Buffer)
6380 {
6381 return GDI_ERROR;
6382 }
6383
6384 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
6385 {
6386 DefChar = 0xffff;
6387 }
6388 else
6389 {
6390 FT_Face Face = FontGDI->SharedFace->Face;
6391 if (FT_IS_SFNT(Face))
6392 {
6393 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
6394 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(Face, pOS2->usDefaultChar) : 0);
6395 }
6396 else
6397 {
6398 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
6399 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
6400 if (!potm)
6401 {
6402 cwc = GDI_ERROR;
6403 goto ErrorRet;
6404 }
6405 IntGetOutlineTextMetrics(FontGDI, Size, potm);
6406 DefChar = potm->otmTextMetrics.tmDefaultChar;
6407 ExFreePoolWithTag(potm, GDITAG_TEXT);
6408 }
6409 }
6410
6411 pwcSize = cwc * sizeof(WCHAR);
6412 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6413
6414 if (!Safepwc)
6415 {
6416 Status = STATUS_NO_MEMORY;
6417 goto ErrorRet;
6418 }
6419
6420 _SEH2_TRY
6421 {
6422 ProbeForRead(UnSafepwc, pwcSize, 1);
6423 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6424 }
6425 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6426 {
6427 Status = _SEH2_GetExceptionCode();
6428 }
6429 _SEH2_END;
6430
6431 if (!NT_SUCCESS(Status)) goto ErrorRet;
6432
6433 IntLockFreeType;
6434
6435 for (i = 0; i < cwc; i++)
6436 {
6437 Buffer[i] = FT_Get_Char_Index(FontGDI->SharedFace->Face, Safepwc[i]);
6438 if (Buffer[i] == 0)
6439 {
6440 Buffer[i] = DefChar;
6441 }
6442 }
6443
6444 IntUnLockFreeType;
6445
6446 _SEH2_TRY
6447 {
6448 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
6449 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
6450 }
6451 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6452 {
6453 Status = _SEH2_GetExceptionCode();
6454 }
6455 _SEH2_END;
6456
6457 ErrorRet:
6458 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6459 if (Safepwc != NULL)
6460 {
6461 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6462 }
6463 if (NT_SUCCESS(Status)) return cwc;
6464 return GDI_ERROR;
6465 }
6466
6467 /* EOF */