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