[WIN32SS] Fix charset in font enumeration. Patch by Katayama Hirofumi MZ. CORE-10876
[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(FreeTypeLock->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 RtlInitUnicodeString(pNameW, NULL);
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 Status = RtlCreateUnicodeString(pNameW, Buf);
2094 break;
2095 }
2096
2097 if (Status == STATUS_NOT_FOUND)
2098 {
2099 if (LangID != gusEnglishUS)
2100 {
2101 Status = IntGetFontLocalizedName(pNameW, Face, NameID, gusEnglishUS);
2102 }
2103 }
2104 if (Status == STATUS_NOT_FOUND)
2105 {
2106 RtlInitAnsiString(&AnsiName, Face->family_name);
2107 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2108 }
2109
2110 return Status;
2111 }
2112
2113 static void FASTCALL
2114 FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
2115 {
2116 ANSI_STRING StyleA;
2117 UNICODE_STRING StyleW;
2118 TT_OS2 *pOS2;
2119 FONTSIGNATURE fs;
2120 CHARSETINFO CharSetInfo;
2121 unsigned i, Size;
2122 OUTLINETEXTMETRICW *Otm;
2123 LOGFONTW *Lf;
2124 TEXTMETRICW *TM;
2125 NEWTEXTMETRICW *Ntm;
2126 DWORD fs0;
2127 NTSTATUS status;
2128 FT_Face Face = FontGDI->SharedFace->Face;
2129
2130 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
2131 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2132 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2133 if (!Otm)
2134 {
2135 return;
2136 }
2137 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2138
2139 Lf = &Info->EnumLogFontEx.elfLogFont;
2140 TM = &Otm->otmTextMetrics;
2141
2142 Lf->lfHeight = TM->tmHeight;
2143 Lf->lfWidth = TM->tmAveCharWidth;
2144 Lf->lfWeight = TM->tmWeight;
2145 Lf->lfItalic = TM->tmItalic;
2146 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
2147 Lf->lfCharSet = TM->tmCharSet;
2148 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
2149 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
2150 Lf->lfQuality = PROOF_QUALITY;
2151
2152 Ntm = &Info->NewTextMetricEx.ntmTm;
2153 Ntm->tmHeight = TM->tmHeight;
2154 Ntm->tmAscent = TM->tmAscent;
2155 Ntm->tmDescent = TM->tmDescent;
2156 Ntm->tmInternalLeading = TM->tmInternalLeading;
2157 Ntm->tmExternalLeading = TM->tmExternalLeading;
2158 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
2159 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
2160 Ntm->tmWeight = TM->tmWeight;
2161 Ntm->tmOverhang = TM->tmOverhang;
2162 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
2163 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
2164 Ntm->tmFirstChar = TM->tmFirstChar;
2165 Ntm->tmLastChar = TM->tmLastChar;
2166 Ntm->tmDefaultChar = TM->tmDefaultChar;
2167 Ntm->tmBreakChar = TM->tmBreakChar;
2168 Ntm->tmItalic = TM->tmItalic;
2169 Ntm->tmUnderlined = TM->tmUnderlined;
2170 Ntm->tmStruckOut = TM->tmStruckOut;
2171 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
2172 Ntm->tmCharSet = TM->tmCharSet;
2173 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
2174
2175 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
2176
2177 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
2178
2179 Ntm->ntmSizeEM = Otm->otmEMSquare;
2180 Ntm->ntmCellHeight = Otm->otmEMSquare;
2181 Ntm->ntmAvgWidth = 0;
2182
2183 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
2184 ? TRUETYPE_FONTTYPE : 0);
2185
2186 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
2187 Info->FontType |= RASTER_FONTTYPE;
2188
2189 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2190
2191 /* face name */
2192 /* TODO: full name */
2193 if (FaceName)
2194 {
2195 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
2196 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
2197 FaceName);
2198 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2199 sizeof(Info->EnumLogFontEx.elfFullName),
2200 FaceName);
2201 }
2202 else
2203 {
2204 UNICODE_STRING NameW;
2205 status = IntGetFontLocalizedName(&NameW, Face, TT_NAME_ID_FONT_FAMILY,
2206 gusLanguageID);
2207 if (NT_SUCCESS(status))
2208 {
2209 /* store it */
2210 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
2211 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
2212 NameW.Buffer);
2213 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
2214 sizeof(Info->EnumLogFontEx.elfFullName),
2215 NameW.Buffer);
2216 RtlFreeUnicodeString(&NameW);
2217 }
2218 }
2219
2220 RtlInitAnsiString(&StyleA, Face->style_name);
2221 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
2222 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
2223 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
2224 if (!NT_SUCCESS(status))
2225 {
2226 return;
2227 }
2228 Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
2229
2230 IntLockFreeType;
2231 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2232
2233 if (!pOS2)
2234 {
2235 IntUnLockFreeType;
2236 return;
2237 }
2238
2239 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2240 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2241 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2242 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2243 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2244 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2245
2246 if (0 == pOS2->version)
2247 {
2248 FT_UInt Dummy;
2249
2250 if (FT_Get_First_Char(Face, &Dummy) < 0x100)
2251 fs.fsCsb[0] |= FS_LATIN1;
2252 else
2253 fs.fsCsb[0] |= FS_SYMBOL;
2254 }
2255 IntUnLockFreeType;
2256
2257 if (fs.fsCsb[0] == 0)
2258 {
2259 /* Let's see if we can find any interesting cmaps */
2260 for (i = 0; i < (UINT)Face->num_charmaps; i++)
2261 {
2262 switch (Face->charmaps[i]->encoding)
2263 {
2264 case FT_ENCODING_UNICODE:
2265 case FT_ENCODING_APPLE_ROMAN:
2266 fs.fsCsb[0] |= FS_LATIN1;
2267 break;
2268 case FT_ENCODING_MS_SYMBOL:
2269 fs.fsCsb[0] |= FS_SYMBOL;
2270 break;
2271 default:
2272 break;
2273 }
2274 }
2275 }
2276
2277 for (i = 0; i < MAXTCIINDEX; i++)
2278 {
2279 fs0 = 1L << i;
2280 if (fs.fsCsb[0] & fs0)
2281 {
2282 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
2283 {
2284 CharSetInfo.ciCharset = DEFAULT_CHARSET;
2285 }
2286 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
2287 {
2288 if (ElfScripts[i])
2289 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
2290 else
2291 {
2292 DPRINT1("Unknown elfscript for bit %u\n", i);
2293 }
2294 }
2295 }
2296 }
2297 Info->NewTextMetricEx.ntmFontSig = fs;
2298 }
2299
2300 static int FASTCALL
2301 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
2302 {
2303 DWORD i;
2304 UNICODE_STRING InfoFaceName;
2305
2306 for (i = 0; i < InfoEntries; i++)
2307 {
2308 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
2309 if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE))
2310 {
2311 return i;
2312 }
2313 }
2314
2315 return -1;
2316 }
2317
2318 static BOOLEAN FASTCALL
2319 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
2320 PFONTFAMILYINFO Info, DWORD InfoEntries)
2321 {
2322 UNICODE_STRING LogFontFaceName;
2323
2324 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
2325 if (0 != LogFontFaceName.Length &&
2326 !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE))
2327 {
2328 return FALSE;
2329 }
2330
2331 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
2332 }
2333
2334 static BOOLEAN FASTCALL
2335 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
2336 PFONTFAMILYINFO Info,
2337 DWORD *Count,
2338 DWORD Size,
2339 PLIST_ENTRY Head)
2340 {
2341 PLIST_ENTRY Entry;
2342 PFONT_ENTRY CurrentEntry;
2343 ANSI_STRING EntryFaceNameA;
2344 UNICODE_STRING EntryFaceNameW;
2345 FONTGDI *FontGDI;
2346 NTSTATUS status;
2347
2348 Entry = Head->Flink;
2349 while (Entry != Head)
2350 {
2351 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2352
2353 FontGDI = CurrentEntry->Font;
2354 ASSERT(FontGDI);
2355
2356 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
2357 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2358 if (!NT_SUCCESS(status))
2359 {
2360 return FALSE;
2361 }
2362
2363 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2364 {
2365 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2366 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2367 }
2368
2369 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
2370 {
2371 if (*Count < Size)
2372 {
2373 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
2374 }
2375 (*Count)++;
2376 }
2377 RtlFreeUnicodeString(&EntryFaceNameW);
2378 Entry = Entry->Flink;
2379 }
2380
2381 return TRUE;
2382 }
2383
2384 typedef struct FontFamilyInfoCallbackContext
2385 {
2386 LPLOGFONTW LogFont;
2387 PFONTFAMILYINFO Info;
2388 DWORD Count;
2389 DWORD Size;
2390 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
2391
2392 _Function_class_(RTL_QUERY_REGISTRY_ROUTINE)
2393 static NTSTATUS APIENTRY
2394 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
2395 IN PVOID ValueData, IN ULONG ValueLength,
2396 IN PVOID Context, IN PVOID EntryContext)
2397 {
2398 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
2399 UNICODE_STRING RegistryName, RegistryValue;
2400 int Existing;
2401 PFONTGDI FontGDI;
2402
2403 if (REG_SZ != ValueType)
2404 {
2405 return STATUS_SUCCESS;
2406 }
2407 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
2408 RtlInitUnicodeString(&RegistryName, ValueName);
2409
2410 /* Do we need to include this font family? */
2411 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
2412 min(InfoContext->Count, InfoContext->Size)))
2413 {
2414 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
2415 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
2416 min(InfoContext->Count, InfoContext->Size));
2417 if (0 <= Existing)
2418 {
2419 /* We already have the information about the "real" font. Just copy it */
2420 if (InfoContext->Count < InfoContext->Size)
2421 {
2422 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
2423 RtlStringCbCopyNW(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
2424 sizeof(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName),
2425 RegistryName.Buffer,
2426 RegistryName.Length);
2427 }
2428 InfoContext->Count++;
2429 return STATUS_SUCCESS;
2430 }
2431
2432 /* Try to find information about the "real" font */
2433 FontGDI = FindFaceNameInLists(&RegistryValue);
2434 if (NULL == FontGDI)
2435 {
2436 /* "Real" font not found, discard this registry entry */
2437 return STATUS_SUCCESS;
2438 }
2439
2440 /* Return info about the "real" font but with the name of the alias */
2441 if (InfoContext->Count < InfoContext->Size)
2442 {
2443 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
2444 RegistryName.Buffer, FontGDI);
2445 }
2446 InfoContext->Count++;
2447 return STATUS_SUCCESS;
2448 }
2449
2450 return STATUS_SUCCESS;
2451 }
2452
2453 static BOOLEAN FASTCALL
2454 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
2455 PFONTFAMILYINFO Info,
2456 DWORD *Count,
2457 DWORD Size)
2458 {
2459 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2460 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
2461 NTSTATUS Status;
2462
2463 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
2464 The real work is done in the registry callback function */
2465 Context.LogFont = LogFont;
2466 Context.Info = Info;
2467 Context.Count = *Count;
2468 Context.Size = Size;
2469
2470 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
2471 QueryTable[0].Flags = 0;
2472 QueryTable[0].Name = NULL;
2473 QueryTable[0].EntryContext = NULL;
2474 QueryTable[0].DefaultType = REG_NONE;
2475 QueryTable[0].DefaultData = NULL;
2476 QueryTable[0].DefaultLength = 0;
2477
2478 QueryTable[1].QueryRoutine = NULL;
2479 QueryTable[1].Name = NULL;
2480
2481 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2482 L"FontSubstitutes",
2483 QueryTable,
2484 &Context,
2485 NULL);
2486 if (NT_SUCCESS(Status))
2487 {
2488 *Count = Context.Count;
2489 }
2490
2491 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
2492 }
2493
2494 BOOL
2495 FASTCALL
2496 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
2497 {
2498 if ( lprs )
2499 {
2500 lprs->nSize = sizeof(RASTERIZER_STATUS);
2501 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
2502 lprs->nLanguageID = gusLanguageID;
2503 return TRUE;
2504 }
2505 EngSetLastError(ERROR_INVALID_PARAMETER);
2506 return FALSE;
2507 }
2508
2509 static
2510 BOOL
2511 SameScaleMatrix(
2512 PMATRIX pmx1,
2513 PMATRIX pmx2)
2514 {
2515 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
2516 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
2517 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
2518 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
2519 }
2520
2521 FT_BitmapGlyph APIENTRY
2522 ftGdiGlyphCacheGet(
2523 FT_Face Face,
2524 INT GlyphIndex,
2525 INT Height,
2526 PMATRIX pmx)
2527 {
2528 PLIST_ENTRY CurrentEntry;
2529 PFONT_CACHE_ENTRY FontEntry;
2530
2531 ASSERT_FREETYPE_LOCK_HELD();
2532
2533 CurrentEntry = FontCacheListHead.Flink;
2534 while (CurrentEntry != &FontCacheListHead)
2535 {
2536 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
2537 if ((FontEntry->Face == Face) &&
2538 (FontEntry->GlyphIndex == GlyphIndex) &&
2539 (FontEntry->Height == Height) &&
2540 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2541 break;
2542 CurrentEntry = CurrentEntry->Flink;
2543 }
2544
2545 if (CurrentEntry == &FontCacheListHead)
2546 {
2547 return NULL;
2548 }
2549
2550 RemoveEntryList(CurrentEntry);
2551 InsertHeadList(&FontCacheListHead, CurrentEntry);
2552 return FontEntry->BitmapGlyph;
2553 }
2554
2555 /* no cache */
2556 FT_BitmapGlyph APIENTRY
2557 ftGdiGlyphSet(
2558 FT_Face Face,
2559 FT_GlyphSlot GlyphSlot,
2560 FT_Render_Mode RenderMode)
2561 {
2562 FT_Glyph Glyph;
2563 INT error;
2564 FT_Bitmap AlignedBitmap;
2565 FT_BitmapGlyph BitmapGlyph;
2566
2567 error = FT_Get_Glyph(GlyphSlot, &Glyph);
2568 if (error)
2569 {
2570 DPRINT1("Failure getting glyph.\n");
2571 return NULL;
2572 }
2573
2574 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2575 if (error)
2576 {
2577 FT_Done_Glyph(Glyph);
2578 DPRINT1("Failure rendering glyph.\n");
2579 return NULL;
2580 }
2581
2582 BitmapGlyph = (FT_BitmapGlyph)Glyph;
2583 FT_Bitmap_New(&AlignedBitmap);
2584 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2585 {
2586 DPRINT1("Conversion failed\n");
2587 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2588 return NULL;
2589 }
2590
2591 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2592 BitmapGlyph->bitmap = AlignedBitmap;
2593
2594 return BitmapGlyph;
2595 }
2596
2597 FT_BitmapGlyph APIENTRY
2598 ftGdiGlyphCacheSet(
2599 FT_Face Face,
2600 INT GlyphIndex,
2601 INT Height,
2602 PMATRIX pmx,
2603 FT_GlyphSlot GlyphSlot,
2604 FT_Render_Mode RenderMode)
2605 {
2606 FT_Glyph GlyphCopy;
2607 INT error;
2608 PFONT_CACHE_ENTRY NewEntry;
2609 FT_Bitmap AlignedBitmap;
2610 FT_BitmapGlyph BitmapGlyph;
2611
2612 ASSERT_FREETYPE_LOCK_HELD();
2613
2614 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2615 if (error)
2616 {
2617 DPRINT1("Failure caching glyph.\n");
2618 return NULL;
2619 };
2620
2621 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2622 if (error)
2623 {
2624 FT_Done_Glyph(GlyphCopy);
2625 DPRINT1("Failure rendering glyph.\n");
2626 return NULL;
2627 };
2628
2629 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
2630 if (!NewEntry)
2631 {
2632 DPRINT1("Alloc failure caching glyph.\n");
2633 FT_Done_Glyph(GlyphCopy);
2634 return NULL;
2635 }
2636
2637 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2638 FT_Bitmap_New(&AlignedBitmap);
2639 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2640 {
2641 DPRINT1("Conversion failed\n");
2642 ExFreePoolWithTag(NewEntry, TAG_FONT);
2643 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2644 return NULL;
2645 }
2646
2647 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2648 BitmapGlyph->bitmap = AlignedBitmap;
2649
2650 NewEntry->GlyphIndex = GlyphIndex;
2651 NewEntry->Face = Face;
2652 NewEntry->BitmapGlyph = BitmapGlyph;
2653 NewEntry->Height = Height;
2654 NewEntry->mxWorldToDevice = *pmx;
2655
2656 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
2657 if (++FontCacheNumEntries > MAX_FONT_CACHE)
2658 {
2659 NewEntry = CONTAINING_RECORD(FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
2660 RemoveCachedEntry(NewEntry);
2661 }
2662
2663 return BitmapGlyph;
2664 }
2665
2666
2667 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2668 {
2669 pt->x.value = vec->x >> 6;
2670 pt->x.fract = (vec->x & 0x3f) << 10;
2671 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2672 pt->y.value = vec->y >> 6;
2673 pt->y.fract = (vec->y & 0x3f) << 10;
2674 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2675 }
2676
2677 /*
2678 This function builds an FT_Fixed from a float. It puts the integer part
2679 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2680 It fails if the integer part of the float number is greater than SHORT_MAX.
2681 */
2682 static __inline FT_Fixed FT_FixedFromFloat(float f)
2683 {
2684 short value = f;
2685 unsigned short fract = (f - value) * 0xFFFF;
2686 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2687 }
2688
2689 /*
2690 This function builds an FT_Fixed from a FIXED. It simply put f.value
2691 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2692 */
2693 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2694 {
2695 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2696 }
2697
2698 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2699 {
2700 TTPOLYGONHEADER *pph;
2701 TTPOLYCURVE *ppc;
2702 int needed = 0, point = 0, contour, first_pt;
2703 unsigned int pph_start, cpfx;
2704 DWORD type;
2705
2706 for (contour = 0; contour < outline->n_contours; contour++)
2707 {
2708 /* Ignore contours containing one point */
2709 if (point == outline->contours[contour])
2710 {
2711 point++;
2712 continue;
2713 }
2714
2715 pph_start = needed;
2716 pph = (TTPOLYGONHEADER *)(buf + needed);
2717 first_pt = point;
2718 if (buf)
2719 {
2720 pph->dwType = TT_POLYGON_TYPE;
2721 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2722 }
2723 needed += sizeof(*pph);
2724 point++;
2725 while (point <= outline->contours[contour])
2726 {
2727 ppc = (TTPOLYCURVE *)(buf + needed);
2728 type = outline->tags[point] & FT_Curve_Tag_On ?
2729 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2730 cpfx = 0;
2731 do
2732 {
2733 if (buf)
2734 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2735 cpfx++;
2736 point++;
2737 } while (point <= outline->contours[contour] &&
2738 (outline->tags[point] & FT_Curve_Tag_On) ==
2739 (outline->tags[point-1] & FT_Curve_Tag_On));
2740 /* At the end of a contour Windows adds the start point, but
2741 only for Beziers */
2742 if (point > outline->contours[contour] &&
2743 !(outline->tags[point-1] & FT_Curve_Tag_On))
2744 {
2745 if (buf)
2746 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2747 cpfx++;
2748 }
2749 else if (point <= outline->contours[contour] &&
2750 outline->tags[point] & FT_Curve_Tag_On)
2751 {
2752 /* add closing pt for bezier */
2753 if (buf)
2754 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2755 cpfx++;
2756 point++;
2757 }
2758 if (buf)
2759 {
2760 ppc->wType = type;
2761 ppc->cpfx = cpfx;
2762 }
2763 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2764 }
2765 if (buf)
2766 pph->cb = needed - pph_start;
2767 }
2768 return needed;
2769 }
2770
2771 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2772 {
2773 /* Convert the quadratic Beziers to cubic Beziers.
2774 The parametric eqn for a cubic Bezier is, from PLRM:
2775 r(t) = at^3 + bt^2 + ct + r0
2776 with the control points:
2777 r1 = r0 + c/3
2778 r2 = r1 + (c + b)/3
2779 r3 = r0 + c + b + a
2780
2781 A quadratic Bezier has the form:
2782 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2783
2784 So equating powers of t leads to:
2785 r1 = 2/3 p1 + 1/3 p0
2786 r2 = 2/3 p1 + 1/3 p2
2787 and of course r0 = p0, r3 = p2
2788 */
2789 int contour, point = 0, first_pt;
2790 TTPOLYGONHEADER *pph;
2791 TTPOLYCURVE *ppc;
2792 DWORD pph_start, cpfx, type;
2793 FT_Vector cubic_control[4];
2794 unsigned int needed = 0;
2795
2796 for (contour = 0; contour < outline->n_contours; contour++)
2797 {
2798 pph_start = needed;
2799 pph = (TTPOLYGONHEADER *)(buf + needed);
2800 first_pt = point;
2801 if (buf)
2802 {
2803 pph->dwType = TT_POLYGON_TYPE;
2804 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2805 }
2806 needed += sizeof(*pph);
2807 point++;
2808 while (point <= outline->contours[contour])
2809 {
2810 ppc = (TTPOLYCURVE *)(buf + needed);
2811 type = outline->tags[point] & FT_Curve_Tag_On ?
2812 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2813 cpfx = 0;
2814 do
2815 {
2816 if (type == TT_PRIM_LINE)
2817 {
2818 if (buf)
2819 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2820 cpfx++;
2821 point++;
2822 }
2823 else
2824 {
2825 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2826 so cpfx = 3n */
2827
2828 /* FIXME: Possible optimization in endpoint calculation
2829 if there are two consecutive curves */
2830 cubic_control[0] = outline->points[point-1];
2831 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2832 {
2833 cubic_control[0].x += outline->points[point].x + 1;
2834 cubic_control[0].y += outline->points[point].y + 1;
2835 cubic_control[0].x >>= 1;
2836 cubic_control[0].y >>= 1;
2837 }
2838 if (point+1 > outline->contours[contour])
2839 cubic_control[3] = outline->points[first_pt];
2840 else
2841 {
2842 cubic_control[3] = outline->points[point+1];
2843 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2844 {
2845 cubic_control[3].x += outline->points[point].x + 1;
2846 cubic_control[3].y += outline->points[point].y + 1;
2847 cubic_control[3].x >>= 1;
2848 cubic_control[3].y >>= 1;
2849 }
2850 }
2851 /* r1 = 1/3 p0 + 2/3 p1
2852 r2 = 1/3 p2 + 2/3 p1 */
2853 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2854 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2855 cubic_control[2] = cubic_control[1];
2856 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2857 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2858 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2859 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2860 if (buf)
2861 {
2862 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2863 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2864 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2865 }
2866 cpfx += 3;
2867 point++;
2868 }
2869 } while (point <= outline->contours[contour] &&
2870 (outline->tags[point] & FT_Curve_Tag_On) ==
2871 (outline->tags[point-1] & FT_Curve_Tag_On));
2872 /* At the end of a contour Windows adds the start point,
2873 but only for Beziers and we've already done that.
2874 */
2875 if (point <= outline->contours[contour] &&
2876 outline->tags[point] & FT_Curve_Tag_On)
2877 {
2878 /* This is the closing pt of a bezier, but we've already
2879 added it, so just inc point and carry on */
2880 point++;
2881 }
2882 if (buf)
2883 {
2884 ppc->wType = type;
2885 ppc->cpfx = cpfx;
2886 }
2887 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2888 }
2889 if (buf)
2890 pph->cb = needed - pph_start;
2891 }
2892 return needed;
2893 }
2894
2895 static INT
2896 IntRequestFontSize(PDC dc, FT_Face face, LONG Width, LONG Height)
2897 {
2898 FT_Size_RequestRec req;
2899
2900 if (Width < 0)
2901 Width = -Width;
2902
2903 if (Height < 0)
2904 {
2905 Height = -Height;
2906 }
2907 if (Height == 0)
2908 {
2909 Height = dc->ppdev->devinfo.lfDefaultFont.lfHeight;
2910 }
2911 if (Height == 0)
2912 {
2913 Height = Width;
2914 }
2915
2916 if (Height < 1)
2917 Height = 1;
2918
2919 if (Width > 0xFFFFU)
2920 Width = 0xFFFFU;
2921 if (Height > 0xFFFFU)
2922 Height = 0xFFFFU;
2923
2924 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
2925 req.width = (FT_Long)(Width << 6);
2926 req.height = (FT_Long)(Height << 6);
2927 req.horiResolution = 0;
2928 req.vertResolution = 0;
2929 return FT_Request_Size(face, &req);
2930 }
2931
2932 BOOL
2933 FASTCALL
2934 TextIntUpdateSize(PDC dc,
2935 PTEXTOBJ TextObj,
2936 PFONTGDI FontGDI,
2937 BOOL bDoLock)
2938 {
2939 FT_Face face;
2940 INT error, n;
2941 FT_CharMap charmap, found;
2942 LOGFONTW *plf;
2943
2944 if (bDoLock)
2945 IntLockFreeType;
2946
2947 face = FontGDI->SharedFace->Face;
2948 if (face->charmap == NULL)
2949 {
2950 DPRINT("WARNING: No charmap selected!\n");
2951 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2952
2953 found = NULL;
2954 for (n = 0; n < face->num_charmaps; n++)
2955 {
2956 charmap = face->charmaps[n];
2957 DPRINT("Found charmap encoding: %i\n", charmap->encoding);
2958 if (charmap->encoding != 0)
2959 {
2960 found = charmap;
2961 break;
2962 }
2963 }
2964 if (!found)
2965 {
2966 DPRINT1("WARNING: Could not find desired charmap!\n");
2967 }
2968 else
2969 {
2970 error = FT_Set_Charmap(face, found);
2971 if (error)
2972 {
2973 DPRINT1("WARNING: Could not set the charmap!\n");
2974 }
2975 }
2976 }
2977
2978 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
2979
2980 error = IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
2981
2982 if (bDoLock)
2983 IntUnLockFreeType;
2984
2985 if (error)
2986 {
2987 DPRINT1("Error in setting pixel sizes: %d\n", error);
2988 return FALSE;
2989 }
2990
2991 return TRUE;
2992 }
2993
2994
2995 /*
2996 * Based on WineEngGetGlyphOutline
2997 *
2998 */
2999 ULONG
3000 FASTCALL
3001 ftGdiGetGlyphOutline(
3002 PDC dc,
3003 WCHAR wch,
3004 UINT iFormat,
3005 LPGLYPHMETRICS pgm,
3006 ULONG cjBuf,
3007 PVOID pvBuf,
3008 LPMAT2 pmat2,
3009 BOOL bIgnoreRotation)
3010 {
3011 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3012 PDC_ATTR pdcattr;
3013 PTEXTOBJ TextObj;
3014 PFONTGDI FontGDI;
3015 HFONT hFont = 0;
3016 GLYPHMETRICS gm;
3017 ULONG Size;
3018 FT_Face ft_face;
3019 FT_UInt glyph_index;
3020 DWORD width, height, pitch, needed = 0;
3021 FT_Bitmap ft_bitmap;
3022 FT_Error error;
3023 INT left, right, top = 0, bottom = 0;
3024 FT_Angle angle = 0;
3025 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3026 FLOAT eM11, widthRatio = 1.0;
3027 FT_Matrix transMat = identityMat;
3028 BOOL needsTransform = FALSE;
3029 INT orientation;
3030 LONG aveWidth;
3031 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3032 OUTLINETEXTMETRICW *potm;
3033 XFORM xForm;
3034 LOGFONTW *plf;
3035
3036 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3037 cjBuf, pvBuf, pmat2);
3038
3039 pdcattr = dc->pdcattr;
3040
3041 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
3042 eM11 = xForm.eM11;
3043
3044 hFont = pdcattr->hlfntNew;
3045 TextObj = RealizeFontInit(hFont);
3046
3047 if (!TextObj)
3048 {
3049 EngSetLastError(ERROR_INVALID_HANDLE);
3050 return GDI_ERROR;
3051 }
3052 FontGDI = ObjToGDI(TextObj->Font, FONT);
3053 ft_face = FontGDI->SharedFace->Face;
3054
3055 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3056 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3057 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3058
3059 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3060 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3061 if (!potm)
3062 {
3063 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3064 TEXTOBJ_UnlockText(TextObj);
3065 return GDI_ERROR;
3066 }
3067 IntGetOutlineTextMetrics(FontGDI, Size, potm);
3068
3069 IntLockFreeType;
3070 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3071 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
3072
3073 TEXTOBJ_UnlockText(TextObj);
3074
3075 if (iFormat & GGO_GLYPH_INDEX)
3076 {
3077 glyph_index = wch;
3078 iFormat &= ~GGO_GLYPH_INDEX;
3079 }
3080 else glyph_index = FT_Get_Char_Index(ft_face, wch);
3081
3082 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3083 load_flags |= FT_LOAD_NO_BITMAP;
3084
3085 if (iFormat & GGO_UNHINTED)
3086 {
3087 load_flags |= FT_LOAD_NO_HINTING;
3088 iFormat &= ~GGO_UNHINTED;
3089 }
3090
3091 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3092 if (error)
3093 {
3094 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3095 IntUnLockFreeType;
3096 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3097 return GDI_ERROR;
3098 }
3099 IntUnLockFreeType;
3100
3101 if (aveWidth && potm)
3102 {
3103 widthRatio = (FLOAT)aveWidth * eM11 /
3104 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
3105 }
3106
3107 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3108 right = (INT)((ft_face->glyph->metrics.horiBearingX +
3109 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3110
3111 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3112 lsb = left >> 6;
3113 bbx = (right - left) >> 6;
3114
3115 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3116
3117 IntLockFreeType;
3118
3119 /* Scaling transform */
3120 /*if (aveWidth)*/
3121 {
3122
3123 FT_Matrix ftmatrix;
3124 FLOATOBJ efTemp;
3125
3126 PMATRIX pmx = DC_pmxWorldToDevice(dc);
3127
3128 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3129 efTemp = pmx->efM11;
3130 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3131 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
3132
3133 efTemp = pmx->efM12;
3134 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3135 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
3136
3137 efTemp = pmx->efM21;
3138 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3139 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
3140
3141 efTemp = pmx->efM22;
3142 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3143 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
3144
3145 FT_Matrix_Multiply(&ftmatrix, &transMat);
3146 needsTransform = TRUE;
3147 }
3148
3149 /* Rotation transform */
3150 if (orientation)
3151 {
3152 FT_Matrix rotationMat;
3153 FT_Vector vecAngle;
3154 DPRINT("Rotation Trans!\n");
3155 angle = FT_FixedFromFloat((float)orientation / 10.0);
3156 FT_Vector_Unit(&vecAngle, angle);
3157 rotationMat.xx = vecAngle.x;
3158 rotationMat.xy = -vecAngle.y;
3159 rotationMat.yx = -rotationMat.xy;
3160 rotationMat.yy = rotationMat.xx;
3161 FT_Matrix_Multiply(&rotationMat, &transMat);
3162 needsTransform = TRUE;
3163 }
3164
3165 /* Extra transformation specified by caller */
3166 if (pmat2)
3167 {
3168 FT_Matrix extraMat;
3169 DPRINT("MAT2 Matrix Trans!\n");
3170 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
3171 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
3172 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
3173 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
3174 FT_Matrix_Multiply(&extraMat, &transMat);
3175 needsTransform = TRUE;
3176 }
3177
3178 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
3179
3180 if (!needsTransform)
3181 {
3182 DPRINT("No Need to be Transformed!\n");
3183 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3184 bottom = (ft_face->glyph->metrics.horiBearingY -
3185 ft_face->glyph->metrics.height) & -64;
3186 gm.gmCellIncX = adv;
3187 gm.gmCellIncY = 0;
3188 }
3189 else
3190 {
3191 INT xc, yc;
3192 FT_Vector vec;
3193 for (xc = 0; xc < 2; xc++)
3194 {
3195 for (yc = 0; yc < 2; yc++)
3196 {
3197 vec.x = (ft_face->glyph->metrics.horiBearingX +
3198 xc * ft_face->glyph->metrics.width);
3199 vec.y = ft_face->glyph->metrics.horiBearingY -
3200 yc * ft_face->glyph->metrics.height;
3201 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
3202 FT_Vector_Transform(&vec, &transMat);
3203 if (xc == 0 && yc == 0)
3204 {
3205 left = right = vec.x;
3206 top = bottom = vec.y;
3207 }
3208 else
3209 {
3210 if (vec.x < left) left = vec.x;
3211 else if (vec.x > right) right = vec.x;
3212 if (vec.y < bottom) bottom = vec.y;
3213 else if (vec.y > top) top = vec.y;
3214 }
3215 }
3216 }
3217 left = left & -64;
3218 right = (right + 63) & -64;
3219 bottom = bottom & -64;
3220 top = (top + 63) & -64;
3221
3222 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3223 vec.x = ft_face->glyph->metrics.horiAdvance;
3224 vec.y = 0;
3225 FT_Vector_Transform(&vec, &transMat);
3226 gm.gmCellIncX = (vec.x+63) >> 6;
3227 gm.gmCellIncY = -((vec.y+63) >> 6);
3228 }
3229 gm.gmBlackBoxX = (right - left) >> 6;
3230 gm.gmBlackBoxY = (top - bottom) >> 6;
3231 gm.gmptGlyphOrigin.x = left >> 6;
3232 gm.gmptGlyphOrigin.y = top >> 6;
3233
3234 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
3235 gm.gmCellIncX, gm.gmCellIncY,
3236 gm.gmBlackBoxX, gm.gmBlackBoxY,
3237 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
3238
3239 IntUnLockFreeType;
3240
3241
3242 if (iFormat == GGO_METRICS)
3243 {
3244 DPRINT("GGO_METRICS Exit!\n");
3245 *pgm = gm;
3246 return 1; /* FIXME */
3247 }
3248
3249 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
3250 {
3251 DPRINT1("Loaded a bitmap\n");
3252 return GDI_ERROR;
3253 }
3254
3255 switch (iFormat)
3256 {
3257 case GGO_BITMAP:
3258 width = gm.gmBlackBoxX;
3259 height = gm.gmBlackBoxY;
3260 pitch = ((width + 31) >> 5) << 2;
3261 needed = pitch * height;
3262
3263 if (!pvBuf || !cjBuf) break;
3264 if (!needed) return GDI_ERROR; /* empty glyph */
3265 if (needed > cjBuf)
3266 return GDI_ERROR;
3267
3268 switch (ft_face->glyph->format)
3269 {
3270 case ft_glyph_format_bitmap:
3271 {
3272 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3273 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
3274 INT h = min( height, ft_face->glyph->bitmap.rows );
3275 while (h--)
3276 {
3277 RtlCopyMemory(dst, src, w);
3278 src += ft_face->glyph->bitmap.pitch;
3279 dst += pitch;
3280 }
3281 break;
3282 }
3283
3284 case ft_glyph_format_outline:
3285 ft_bitmap.width = width;
3286 ft_bitmap.rows = height;
3287 ft_bitmap.pitch = pitch;
3288 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
3289 ft_bitmap.buffer = pvBuf;
3290
3291 IntLockFreeType;
3292 if (needsTransform)
3293 {
3294 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3295 }
3296 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3297 /* Note: FreeType will only set 'black' bits for us. */
3298 RtlZeroMemory(pvBuf, needed);
3299 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3300 IntUnLockFreeType;
3301 break;
3302
3303 default:
3304 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3305 return GDI_ERROR;
3306 }
3307 break;
3308
3309 case GGO_GRAY2_BITMAP:
3310 case GGO_GRAY4_BITMAP:
3311 case GGO_GRAY8_BITMAP:
3312 {
3313 unsigned int mult, row, col;
3314 BYTE *start, *ptr;
3315
3316 width = gm.gmBlackBoxX;
3317 height = gm.gmBlackBoxY;
3318 pitch = (width + 3) / 4 * 4;
3319 needed = pitch * height;
3320
3321 if (!pvBuf || !cjBuf) break;
3322 if (!needed) return GDI_ERROR; /* empty glyph */
3323 if (needed > cjBuf)
3324 return GDI_ERROR;
3325
3326 switch (ft_face->glyph->format)
3327 {
3328 case ft_glyph_format_bitmap:
3329 {
3330 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3331 INT h = min( height, ft_face->glyph->bitmap.rows );
3332 INT x;
3333 while (h--)
3334 {
3335 for (x = 0; (UINT)x < pitch; x++)
3336 {
3337 if (x < ft_face->glyph->bitmap.width)
3338 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3339 else
3340 dst[x] = 0;
3341 }
3342 src += ft_face->glyph->bitmap.pitch;
3343 dst += pitch;
3344 }
3345 break;
3346 }
3347 case ft_glyph_format_outline:
3348 {
3349 ft_bitmap.width = width;
3350 ft_bitmap.rows = height;
3351 ft_bitmap.pitch = pitch;
3352 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3353 ft_bitmap.buffer = pvBuf;
3354
3355 IntLockFreeType;
3356 if (needsTransform)
3357 {
3358 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3359 }
3360 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3361 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
3362 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3363 IntUnLockFreeType;
3364
3365 if (iFormat == GGO_GRAY2_BITMAP)
3366 mult = 4;
3367 else if (iFormat == GGO_GRAY4_BITMAP)
3368 mult = 16;
3369 else if (iFormat == GGO_GRAY8_BITMAP)
3370 mult = 64;
3371 else
3372 {
3373 return GDI_ERROR;
3374 }
3375
3376 start = pvBuf;
3377 for (row = 0; row < height; row++)
3378 {
3379 ptr = start;
3380 for (col = 0; col < width; col++, ptr++)
3381 {
3382 *ptr = (((int)*ptr) * mult + 128) / 256;
3383 }
3384 start += pitch;
3385 }
3386
3387 break;
3388 }
3389 default:
3390 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3391 return GDI_ERROR;
3392 }
3393 }
3394
3395 case GGO_NATIVE:
3396 {
3397 FT_Outline *outline = &ft_face->glyph->outline;
3398
3399 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
3400
3401 IntLockFreeType;
3402 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
3403
3404 needed = get_native_glyph_outline(outline, cjBuf, NULL);
3405
3406 if (!pvBuf || !cjBuf)
3407 {
3408 IntUnLockFreeType;
3409 break;
3410 }
3411 if (needed > cjBuf)
3412 {
3413 IntUnLockFreeType;
3414 return GDI_ERROR;
3415 }
3416 get_native_glyph_outline(outline, cjBuf, pvBuf);
3417 IntUnLockFreeType;
3418 break;
3419 }
3420 case GGO_BEZIER:
3421 {
3422 FT_Outline *outline = &ft_face->glyph->outline;
3423 if (cjBuf == 0) pvBuf = NULL;
3424
3425 if (needsTransform && pvBuf)
3426 {
3427 IntLockFreeType;
3428 FT_Outline_Transform(outline, &transMat);
3429 IntUnLockFreeType;
3430 }
3431 needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
3432
3433 if (!pvBuf || !cjBuf)
3434 break;
3435 if (needed > cjBuf)
3436 return GDI_ERROR;
3437
3438 get_bezier_glyph_outline(outline, cjBuf, pvBuf);
3439 break;
3440 }
3441
3442 default:
3443 DPRINT1("Unsupported format %u\n", iFormat);
3444 return GDI_ERROR;
3445 }
3446
3447 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
3448 *pgm = gm;
3449 return needed;
3450 }
3451
3452 BOOL
3453 FASTCALL
3454 TextIntGetTextExtentPoint(PDC dc,
3455 PTEXTOBJ TextObj,
3456 LPCWSTR String,
3457 INT Count,
3458 ULONG MaxExtent,
3459 LPINT Fit,
3460 LPINT Dx,
3461 LPSIZE Size,
3462 FLONG fl)
3463 {
3464 PFONTGDI FontGDI;
3465 FT_Face face;
3466 FT_GlyphSlot glyph;
3467 FT_BitmapGlyph realglyph;
3468 INT error, glyph_index, i, previous;
3469 ULONGLONG TotalWidth = 0;
3470 BOOL use_kerning;
3471 FT_Render_Mode RenderMode;
3472 BOOLEAN Render;
3473 PMATRIX pmxWorldToDevice;
3474 LOGFONTW *plf;
3475 BOOL EmuBold, EmuItalic;
3476
3477 FontGDI = ObjToGDI(TextObj->Font, FONT);
3478
3479 face = FontGDI->SharedFace->Face;
3480 if (NULL != Fit)
3481 {
3482 *Fit = 0;
3483 }
3484
3485 IntLockFreeType;
3486
3487 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3488
3489 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3490 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
3491 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
3492
3493 Render = IntIsFontRenderingEnabled();
3494 if (Render)
3495 RenderMode = IntGetFontRenderMode(plf);
3496 else
3497 RenderMode = FT_RENDER_MODE_MONO;
3498
3499
3500 /* Get the DC's world-to-device transformation matrix */
3501 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3502 FtSetCoordinateTransform(face, pmxWorldToDevice);
3503
3504 use_kerning = FT_HAS_KERNING(face);
3505 previous = 0;
3506
3507 for (i = 0; i < Count; i++)
3508 {
3509 if (fl & GTEF_INDICES)
3510 glyph_index = *String;
3511 else
3512 glyph_index = FT_Get_Char_Index(face, *String);
3513
3514 if (EmuBold || EmuItalic)
3515 realglyph = NULL;
3516 else
3517 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3518 plf->lfHeight, pmxWorldToDevice);
3519
3520 if (EmuBold || EmuItalic || !realglyph)
3521 {
3522 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3523 if (error)
3524 {
3525 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
3526 break;
3527 }
3528
3529 glyph = face->glyph;
3530 if (EmuBold || EmuItalic)
3531 {
3532 if (EmuBold)
3533 FT_GlyphSlot_Embolden(glyph);
3534 if (EmuItalic)
3535 FT_GlyphSlot_Oblique(glyph);
3536 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
3537 }
3538 else
3539 {
3540 realglyph = ftGdiGlyphCacheSet(face,
3541 glyph_index,
3542 plf->lfHeight,
3543 pmxWorldToDevice,
3544 glyph,
3545 RenderMode);
3546 }
3547
3548 if (!realglyph)
3549 {
3550 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3551 break;
3552 }
3553 }
3554
3555 /* Retrieve kerning distance */
3556 if (use_kerning && previous && glyph_index)
3557 {
3558 FT_Vector delta;
3559 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3560 TotalWidth += delta.x;
3561 }
3562
3563 TotalWidth += realglyph->root.advance.x >> 10;
3564
3565 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
3566 {
3567 *Fit = i + 1;
3568 }
3569 if (NULL != Dx)
3570 {
3571 Dx[i] = (TotalWidth + 32) >> 6;
3572 }
3573
3574 if (EmuBold || EmuItalic)
3575 {
3576 FT_Done_Glyph((FT_Glyph)realglyph);
3577 realglyph = NULL;
3578 }
3579
3580 previous = glyph_index;
3581 String++;
3582 }
3583 IntUnLockFreeType;
3584
3585 Size->cx = (TotalWidth + 32) >> 6;
3586 Size->cy = (plf->lfHeight == 0 ?
3587 dc->ppdev->devinfo.lfDefaultFont.lfHeight :
3588 abs(plf->lfHeight));
3589 Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
3590
3591 return TRUE;
3592 }
3593
3594
3595 INT
3596 FASTCALL
3597 ftGdiGetTextCharsetInfo(
3598 PDC Dc,
3599 LPFONTSIGNATURE lpSig,
3600 DWORD dwFlags)
3601 {
3602 PDC_ATTR pdcattr;
3603 UINT Ret = DEFAULT_CHARSET;
3604 INT i;
3605 HFONT hFont;
3606 PTEXTOBJ TextObj;
3607 PFONTGDI FontGdi;
3608 FONTSIGNATURE fs;
3609 TT_OS2 *pOS2;
3610 FT_Face Face;
3611 CHARSETINFO csi;
3612 DWORD cp, fs0;
3613 USHORT usACP, usOEM;
3614
3615 pdcattr = Dc->pdcattr;
3616 hFont = pdcattr->hlfntNew;
3617 TextObj = RealizeFontInit(hFont);
3618
3619 if (!TextObj)
3620 {
3621 EngSetLastError(ERROR_INVALID_HANDLE);
3622 return Ret;
3623 }
3624 FontGdi = ObjToGDI(TextObj->Font, FONT);
3625 Face = FontGdi->SharedFace->Face;
3626 TEXTOBJ_UnlockText(TextObj);
3627
3628 IntLockFreeType;
3629 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3630 IntUnLockFreeType;
3631 memset(&fs, 0, sizeof(FONTSIGNATURE));
3632 if (NULL != pOS2)
3633 {
3634 fs.fsCsb[0] = pOS2->ulCodePageRange1;
3635 fs.fsCsb[1] = pOS2->ulCodePageRange2;
3636 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3637 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3638 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3639 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3640 if (pOS2->version == 0)
3641 {
3642 FT_UInt dummy;
3643
3644 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
3645 fs.fsCsb[0] |= FS_LATIN1;
3646 else
3647 fs.fsCsb[0] |= FS_SYMBOL;
3648 }
3649 }
3650 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
3651 if (fs.fsCsb[0] == 0)
3652 { /* Let's see if we can find any interesting cmaps */
3653 for (i = 0; i < Face->num_charmaps; i++)
3654 {
3655 switch (Face->charmaps[i]->encoding)
3656 {
3657 case FT_ENCODING_UNICODE:
3658 case FT_ENCODING_APPLE_ROMAN:
3659 fs.fsCsb[0] |= FS_LATIN1;
3660 break;
3661 case FT_ENCODING_MS_SYMBOL:
3662 fs.fsCsb[0] |= FS_SYMBOL;
3663 break;
3664 default:
3665 break;
3666 }
3667 }
3668 }
3669 if (lpSig)
3670 {
3671 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
3672 }
3673
3674 RtlGetDefaultCodePage(&usACP, &usOEM);
3675 cp = usACP;
3676
3677 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
3678 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
3679 {
3680 DPRINT("Hit 1\n");
3681 Ret = csi.ciCharset;
3682 goto Exit;
3683 }
3684
3685 for (i = 0; i < MAXTCIINDEX; i++)
3686 {
3687 fs0 = 1L << i;
3688 if (fs.fsCsb[0] & fs0)
3689 {
3690 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
3691 {
3692 // *cp = csi.ciACP;
3693 DPRINT("Hit 2\n");
3694 Ret = csi.ciCharset;
3695 goto Exit;
3696 }
3697 else
3698 DPRINT1("TCI failing on %x\n", fs0);
3699 }
3700 }
3701 Exit:
3702 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
3703 return (MAKELONG(csi.ciACP, csi.ciCharset));
3704 }
3705
3706
3707 DWORD
3708 FASTCALL
3709 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
3710 {
3711 DWORD size = 0;
3712 DWORD num_ranges = 0;
3713 FT_Face face = Font->SharedFace->Face;
3714
3715 if (face->charmap->encoding == FT_ENCODING_UNICODE)
3716 {
3717 FT_UInt glyph_code = 0;
3718 FT_ULong char_code, char_code_prev;
3719
3720 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
3721
3722 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3723 face->num_glyphs, glyph_code, char_code);
3724
3725 if (!glyph_code) return 0;
3726
3727 if (glyphset)
3728 {
3729 glyphset->ranges[0].wcLow = (USHORT)char_code;
3730 glyphset->ranges[0].cGlyphs = 0;
3731 glyphset->cGlyphsSupported = 0;
3732 }
3733
3734 num_ranges = 1;
3735 while (glyph_code)
3736 {
3737 if (char_code < char_code_prev)
3738 {
3739 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
3740 return 0;
3741 }
3742 if (char_code - char_code_prev > 1)
3743 {
3744 num_ranges++;
3745 if (glyphset)
3746 {
3747 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
3748 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
3749 glyphset->cGlyphsSupported++;
3750 }
3751 }
3752 else if (glyphset)
3753 {
3754 glyphset->ranges[num_ranges - 1].cGlyphs++;
3755 glyphset->cGlyphsSupported++;
3756 }
3757 char_code_prev = char_code;
3758 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
3759 }
3760 }
3761 else
3762 DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
3763
3764 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
3765 if (glyphset)
3766 {
3767 glyphset->cbThis = size;
3768 glyphset->cRanges = num_ranges;
3769 glyphset->flAccel = 0;
3770 }
3771 return size;
3772 }
3773
3774
3775 BOOL
3776 FASTCALL
3777 ftGdiGetTextMetricsW(
3778 HDC hDC,
3779 PTMW_INTERNAL ptmwi)
3780 {
3781 PDC dc;
3782 PDC_ATTR pdcattr;
3783 PTEXTOBJ TextObj;
3784 PFONTGDI FontGDI;
3785 FT_Face Face;
3786 TT_OS2 *pOS2;
3787 TT_HoriHeader *pHori;
3788 FT_WinFNT_HeaderRec Win;
3789 ULONG Error;
3790 NTSTATUS Status = STATUS_SUCCESS;
3791 LOGFONTW *plf;
3792
3793 if (!ptmwi)
3794 {
3795 EngSetLastError(STATUS_INVALID_PARAMETER);
3796 return FALSE;
3797 }
3798
3799 if (!(dc = DC_LockDc(hDC)))
3800 {
3801 EngSetLastError(ERROR_INVALID_HANDLE);
3802 return FALSE;
3803 }
3804 pdcattr = dc->pdcattr;
3805 TextObj = RealizeFontInit(pdcattr->hlfntNew);
3806 if (NULL != TextObj)
3807 {
3808 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3809 FontGDI = ObjToGDI(TextObj->Font, FONT);
3810
3811 Face = FontGDI->SharedFace->Face;
3812 IntLockFreeType;
3813 Error = IntRequestFontSize(dc, Face, plf->lfWidth, plf->lfHeight);
3814 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
3815 IntUnLockFreeType;
3816 if (0 != Error)
3817 {
3818 DPRINT1("Error in setting pixel sizes: %u\n", Error);
3819 Status = STATUS_UNSUCCESSFUL;
3820 }
3821 else
3822 {
3823 FT_Face Face = FontGDI->SharedFace->Face;
3824 Status = STATUS_SUCCESS;
3825
3826 IntLockFreeType;
3827 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3828 if (NULL == pOS2)
3829 {
3830 DPRINT1("Can't find OS/2 table - not TT font?\n");
3831 Status = STATUS_INTERNAL_ERROR;
3832 }
3833
3834 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
3835 if (NULL == pHori)
3836 {
3837 DPRINT1("Can't find HHEA table - not TT font?\n");
3838 Status = STATUS_INTERNAL_ERROR;
3839 }
3840
3841 Error = FT_Get_WinFNT_Header(Face, &Win);
3842
3843 IntUnLockFreeType;
3844
3845 if (NT_SUCCESS(Status))
3846 {
3847 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
3848
3849 /* FIXME: Fill Diff member */
3850 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
3851 }
3852 }
3853 TEXTOBJ_UnlockText(TextObj);
3854 }
3855 else
3856 {
3857 Status = STATUS_INVALID_HANDLE;
3858 }
3859 DC_UnlockDc(dc);
3860
3861 if (!NT_SUCCESS(Status))
3862 {
3863 SetLastNtError(Status);
3864 return FALSE;
3865 }
3866 return TRUE;
3867 }
3868
3869 DWORD
3870 FASTCALL
3871 ftGdiGetFontData(
3872 PFONTGDI FontGdi,
3873 DWORD Table,
3874 DWORD Offset,
3875 PVOID Buffer,
3876 DWORD Size)
3877 {
3878 DWORD Result = GDI_ERROR;
3879 FT_Face Face = FontGdi->SharedFace->Face;
3880
3881 IntLockFreeType;
3882
3883 if (FT_IS_SFNT(Face))
3884 {
3885 if (Table)
3886 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
3887 (Table << 8 & 0xFF0000);
3888
3889 if (!Buffer) Size = 0;
3890
3891 if (Buffer && Size)
3892 {
3893 FT_Error Error;
3894 FT_ULong Needed = 0;
3895
3896 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
3897
3898 if ( !Error && Needed < Size) Size = Needed;
3899 }
3900 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
3901 Result = Size;
3902 }
3903
3904 IntUnLockFreeType;
3905
3906 return Result;
3907 }
3908
3909 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
3910 static UINT FASTCALL
3911 GetFontPenalty(LOGFONTW * LogFont,
3912 PUNICODE_STRING RequestedNameW,
3913 PUNICODE_STRING ActualNameW,
3914 PUNICODE_STRING FullFaceNameW,
3915 BYTE RequestedCharSet,
3916 PFONTGDI FontGDI,
3917 OUTLINETEXTMETRICW * Otm,
3918 TEXTMETRICW * TM,
3919 const char * style_name)
3920 {
3921 ULONG Penalty = 0;
3922 BYTE Byte;
3923 LONG Long;
3924 BOOL fFixedSys = FALSE, fNeedScaling = FALSE;
3925 const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
3926 NTSTATUS Status;
3927
3928 /* FIXME: Aspect Penalty 30 */
3929 /* FIXME: IntSizeSynth Penalty 20 */
3930 /* FIXME: SmallPenalty Penalty 1 */
3931 /* FIXME: FaceNameSubst Penalty 500 */
3932
3933 if (RtlEqualUnicodeString(RequestedNameW, &SystemW, TRUE))
3934 {
3935 /* "System" font */
3936 if (TM->tmCharSet != UserCharSet)
3937 {
3938 /* CharSet Penalty 65000 */
3939 /* Requested charset does not match the candidate's. */
3940 Penalty += 65000;
3941 }
3942 }
3943 else if (RtlEqualUnicodeString(RequestedNameW, &FixedSysW, TRUE))
3944 {
3945 /* "FixedSys" font */
3946 if (TM->tmCharSet != UserCharSet)
3947 {
3948 /* CharSet Penalty 65000 */
3949 /* Requested charset does not match the candidate's. */
3950 Penalty += 65000;
3951 }
3952 fFixedSys = TRUE;
3953 }
3954 else /* Request is non-"System" font */
3955 {
3956 Byte = RequestedCharSet;
3957 if (Byte == DEFAULT_CHARSET)
3958 {
3959 if (RtlEqualUnicodeString(RequestedNameW, &MarlettW, TRUE))
3960 {
3961 if (Byte == ANSI_CHARSET)
3962 {
3963 DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
3964 }
3965 /* We assume SYMBOL_CHARSET for "Marlett" font */
3966 Byte = SYMBOL_CHARSET;
3967 }
3968 }
3969
3970 if (Byte != TM->tmCharSet)
3971 {
3972 if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
3973 {
3974 /* CharSet Penalty 65000 */
3975 /* Requested charset does not match the candidate's. */
3976 Penalty += 65000;
3977 }
3978 else
3979 {
3980 if (UserCharSet != TM->tmCharSet)
3981 {
3982 /* UNDOCUMENTED */
3983 Penalty += 100;
3984 if (ANSI_CHARSET != TM->tmCharSet)
3985 {
3986 /* UNDOCUMENTED */
3987 Penalty += 100;
3988 }
3989 }
3990 }
3991 }
3992 }
3993
3994 Byte = LogFont->lfOutPrecision;
3995 if (Byte == OUT_DEFAULT_PRECIS)
3996 Byte = OUT_OUTLINE_PRECIS; /* Is it OK? */
3997 switch (Byte)
3998 {
3999 case OUT_DEVICE_PRECIS:
4000 if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
4001 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
4002 {
4003 /* OutputPrecision Penalty 19000 */
4004 /* Requested OUT_STROKE_PRECIS, but the device can't do it
4005 or the candidate is not a vector font. */
4006 Penalty += 19000;
4007 }
4008 break;
4009 default:
4010 if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
4011 {
4012 /* OutputPrecision Penalty 19000 */
4013 /* Or OUT_STROKE_PRECIS not requested, and the candidate
4014 is a vector font that requires GDI support. */
4015 Penalty += 19000;
4016 }
4017 break;
4018 }
4019
4020 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4021 if (Byte == DEFAULT_PITCH)
4022 Byte = VARIABLE_PITCH;
4023 if (fFixedSys)
4024 {
4025 /* "FixedSys" font should be fixed-pitch */
4026 Byte = FIXED_PITCH;
4027 }
4028 if (Byte == FIXED_PITCH)
4029 {
4030 if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
4031 {
4032 /* FixedPitch Penalty 15000 */
4033 /* Requested a fixed pitch font, but the candidate is a
4034 variable pitch font. */
4035 Penalty += 15000;
4036 }
4037 }
4038 if (Byte == VARIABLE_PITCH)
4039 {
4040 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4041 {
4042 /* PitchVariable Penalty 350 */
4043 /* Requested a variable pitch font, but the candidate is not a
4044 variable pitch font. */
4045 Penalty += 350;
4046 }
4047 }
4048
4049 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4050 if (Byte == DEFAULT_PITCH)
4051 {
4052 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4053 {
4054 /* DefaultPitchFixed Penalty 1 */
4055 /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
4056 Penalty += 1;
4057 }
4058 }
4059
4060 if (RequestedNameW->Buffer[0])
4061 {
4062 BOOL Found = FALSE;
4063 FT_Face Face = FontGDI->SharedFace->Face;
4064
4065 /* localized family name */
4066 if (!Found)
4067 {
4068 Status = IntGetFontLocalizedName(ActualNameW, Face, TT_NAME_ID_FONT_FAMILY,
4069 gusLanguageID);
4070 if (NT_SUCCESS(Status))
4071 {
4072 Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
4073 }
4074 }
4075 /* localized full name */
4076 if (!Found)
4077 {
4078 Status = IntGetFontLocalizedName(ActualNameW, Face, TT_NAME_ID_FULL_NAME,
4079 gusLanguageID);
4080 if (NT_SUCCESS(Status))
4081 {
4082 Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
4083 }
4084 }
4085 if (gusLanguageID != gusEnglishUS)
4086 {
4087 /* English family name */
4088 if (!Found)
4089 {
4090 Status = IntGetFontLocalizedName(ActualNameW, Face, TT_NAME_ID_FONT_FAMILY,
4091 gusEnglishUS);
4092 if (NT_SUCCESS(Status))
4093 {
4094 Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
4095 }
4096 }
4097 /* English full name */
4098 if (!Found)
4099 {
4100 Status = IntGetFontLocalizedName(ActualNameW, Face, TT_NAME_ID_FULL_NAME,
4101 gusEnglishUS);
4102 if (NT_SUCCESS(Status))
4103 {
4104 Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
4105 }
4106 }
4107 }
4108 if (!Found)
4109 {
4110 /* FaceName Penalty 10000 */
4111 /* Requested a face name, but the candidate's face name
4112 does not match. */
4113 Penalty += 10000;
4114 }
4115 }
4116
4117 Byte = (LogFont->lfPitchAndFamily & 0xF0);
4118 if (Byte != FF_DONTCARE)
4119 {
4120 if (Byte != (TM->tmPitchAndFamily & 0xF0))
4121 {
4122 /* Family Penalty 9000 */
4123 /* Requested a family, but the candidate's family is different. */
4124 Penalty += 9000;
4125 }
4126 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
4127 {
4128 /* FamilyUnknown Penalty 8000 */
4129 /* Requested a family, but the candidate has no family. */
4130 Penalty += 8000;
4131 }
4132 }
4133
4134 /* Is the candidate a non-vector font? */
4135 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4136 {
4137 /* Is lfHeight specified? */
4138 if (LogFont->lfHeight != 0)
4139 {
4140 if (labs(LogFont->lfHeight) < TM->tmHeight)
4141 {
4142 /* HeightBigger Penalty 600 */
4143 /* The candidate is a nonvector font and is bigger than the
4144 requested height. */
4145 Penalty += 600;
4146 /* HeightBiggerDifference Penalty 150 */
4147 /* The candidate is a raster font and is larger than the
4148 requested height. Penalty * height difference */
4149 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4150
4151 fNeedScaling = TRUE;
4152 }
4153 if (TM->tmHeight < labs(LogFont->lfHeight))
4154 {
4155 /* HeightSmaller Penalty 150 */
4156 /* The candidate is a raster font and is smaller than the
4157 requested height. Penalty * height difference */
4158 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4159
4160 fNeedScaling = TRUE;
4161 }
4162 }
4163 }
4164
4165 switch (LogFont->lfPitchAndFamily & 0xF0)
4166 {
4167 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4168 switch (TM->tmPitchAndFamily & 0xF0)
4169 {
4170 case FF_DECORATIVE: case FF_SCRIPT:
4171 /* FamilyUnlikely Penalty 50 */
4172 /* Requested a roman/modern/swiss family, but the
4173 candidate is decorative/script. */
4174 Penalty += 50;
4175 break;
4176 default:
4177 break;
4178 }
4179 break;
4180 case FF_DECORATIVE: case FF_SCRIPT:
4181 switch (TM->tmPitchAndFamily & 0xF0)
4182 {
4183 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4184 /* FamilyUnlikely Penalty 50 */
4185 /* Or requested decorative/script, and the candidate is
4186 roman/modern/swiss. */
4187 Penalty += 50;
4188 break;
4189 default:
4190 break;
4191 }
4192 default:
4193 break;
4194 }
4195
4196 if (LogFont->lfWidth != 0)
4197 {
4198 if (LogFont->lfWidth != TM->tmAveCharWidth)
4199 {
4200 /* Width Penalty 50 */
4201 /* Requested a nonzero width, but the candidate's width
4202 doesn't match. Penalty * width difference */
4203 Penalty += 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth);
4204
4205 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4206 fNeedScaling = TRUE;
4207 }
4208 }
4209
4210 if (fNeedScaling)
4211 {
4212 /* SizeSynth Penalty 50 */
4213 /* The candidate is a raster font that needs scaling by GDI. */
4214 Penalty += 50;
4215 }
4216
4217 if (!!LogFont->lfItalic != !!TM->tmItalic)
4218 {
4219 if (!LogFont->lfItalic && ItalicFromStyle(style_name))
4220 {
4221 /* Italic Penalty 4 */
4222 /* Requested font and candidate font do not agree on italic status,
4223 and the desired result cannot be simulated. */
4224 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
4225 Penalty += 40;
4226 }
4227 else if (LogFont->lfItalic && !ItalicFromStyle(style_name))
4228 {
4229 /* ItalicSim Penalty 1 */
4230 /* Requested italic font but the candidate is not italic,
4231 although italics can be simulated. */
4232 Penalty += 1;
4233 }
4234 }
4235
4236 if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
4237 {
4238 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
4239 {
4240 /* NotTrueType Penalty 4 */
4241 /* Requested OUT_TT_PRECIS, but the candidate is not a
4242 TrueType font. */
4243 Penalty += 4;
4244 }
4245 }
4246
4247 Long = LogFont->lfWeight;
4248 if (LogFont->lfWeight == FW_DONTCARE)
4249 Long = FW_NORMAL;
4250 if (Long != TM->tmWeight)
4251 {
4252 /* Weight Penalty 3 */
4253 /* The candidate's weight does not match the requested weight.
4254 Penalty * (weight difference/10) */
4255 Penalty += 3 * (labs(Long - TM->tmWeight) / 10);
4256 }
4257
4258 if (!LogFont->lfUnderline && TM->tmUnderlined)
4259 {
4260 /* Underline Penalty 3 */
4261 /* Requested font has no underline, but the candidate is
4262 underlined. */
4263 Penalty += 3;
4264 }
4265
4266 if (!LogFont->lfStrikeOut && TM->tmStruckOut)
4267 {
4268 /* StrikeOut Penalty 3 */
4269 /* Requested font has no strike-out, but the candidate is
4270 struck out. */
4271 Penalty += 3;
4272 }
4273
4274 /* Is the candidate a non-vector font? */
4275 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4276 {
4277 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
4278 {
4279 /* VectorHeightSmaller Penalty 2 */
4280 /* Candidate is a vector font that is smaller than the
4281 requested height. Penalty * height difference */
4282 Penalty += 2 * labs(TM->tmHeight - LogFont->lfHeight);
4283 }
4284 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
4285 {
4286 /* VectorHeightBigger Penalty 1 */
4287 /* Candidate is a vector font that is bigger than the
4288 requested height. Penalty * height difference */
4289 Penalty += 1 * labs(TM->tmHeight - LogFont->lfHeight);
4290 }
4291 }
4292
4293 if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
4294 {
4295 /* DeviceFavor Penalty 2 */
4296 /* Extra penalty for all nondevice fonts. */
4297 Penalty += 2;
4298 }
4299
4300 if (Penalty < 200)
4301 {
4302 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
4303 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
4304 "tmCharSet:%d, tmWeight:%ld\n",
4305 Penalty, RequestedNameW->Buffer, ActualNameW->Buffer,
4306 LogFont->lfCharSet, LogFont->lfWeight,
4307 TM->tmCharSet, TM->tmWeight);
4308 }
4309
4310 return Penalty; /* success */
4311 }
4312
4313 static __inline VOID
4314 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, LOGFONTW *LogFont,
4315 PUNICODE_STRING pRequestedNameW,
4316 PUNICODE_STRING pActualNameW, BYTE RequestedCharSet,
4317 PLIST_ENTRY Head)
4318 {
4319 ULONG Penalty;
4320 NTSTATUS Status;
4321 PLIST_ENTRY Entry;
4322 PFONT_ENTRY CurrentEntry;
4323 FONTGDI *FontGDI;
4324 ANSI_STRING ActualNameA;
4325 UNICODE_STRING ActualNameW, FullFaceNameW;
4326 OUTLINETEXTMETRICW *Otm = NULL;
4327 UINT OtmSize, OldOtmSize = 0;
4328 TEXTMETRICW *TM;
4329 FT_Face Face;
4330 LPBYTE pb;
4331
4332 ASSERT(FontObj);
4333 ASSERT(MatchPenalty);
4334 ASSERT(LogFont);
4335 ASSERT(pRequestedNameW);
4336 ASSERT(Head);
4337
4338 /* get the FontObj of lowest penalty */
4339 Entry = Head->Flink;
4340 while (Entry != Head)
4341 {
4342 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
4343 FontGDI = CurrentEntry->Font;
4344 ASSERT(FontGDI);
4345 Face = FontGDI->SharedFace->Face;
4346
4347 /* create actual name */
4348 RtlInitAnsiString(&ActualNameA, Face->family_name);
4349 Status = RtlAnsiStringToUnicodeString(&ActualNameW, &ActualNameA, TRUE);
4350 if (!NT_SUCCESS(Status))
4351 {
4352 /* next entry */
4353 Entry = Entry->Flink;
4354 continue;
4355 }
4356
4357 /* get text metrics */
4358 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4359 if (OtmSize > OldOtmSize)
4360 {
4361 if (Otm)
4362 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4363 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
4364 }
4365
4366 /* update FontObj if lowest penalty */
4367 if (Otm)
4368 {
4369 IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
4370 TM = &Otm->otmTextMetrics;
4371 OldOtmSize = OtmSize;
4372
4373 /* create full name */
4374 pb = (LPBYTE)Otm + (WORD)(DWORD_PTR)Otm->otmpFullName;
4375 Status = RtlCreateUnicodeString(&FullFaceNameW, (LPWSTR)pb);
4376 if (!NT_SUCCESS(Status))
4377 {
4378 RtlFreeUnicodeString(&ActualNameW);
4379 RtlFreeUnicodeString(&FullFaceNameW);
4380 /* next entry */
4381 Entry = Entry->Flink;
4382 continue;
4383 }
4384
4385 Penalty = GetFontPenalty(LogFont, pRequestedNameW, &ActualNameW,
4386 &FullFaceNameW, RequestedCharSet,
4387 FontGDI, Otm, TM, Face->style_name);
4388 if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
4389 {
4390 DPRINT("%ls Penalty: %lu\n", FullFaceNameW.Buffer, Penalty);
4391 RtlFreeUnicodeString(pActualNameW);
4392 RtlCreateUnicodeString(pActualNameW, ActualNameW.Buffer);
4393
4394 *FontObj = GDIToObj(FontGDI, FONT);
4395 *MatchPenalty = Penalty;
4396 }
4397
4398 RtlFreeUnicodeString(&FullFaceNameW);
4399 }
4400
4401 /* free strings */
4402 RtlFreeUnicodeString(&ActualNameW);
4403
4404 /* next entry */
4405 Entry = Entry->Flink;
4406 }
4407
4408 if (Otm)
4409 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4410 }
4411
4412 static
4413 VOID
4414 FASTCALL
4415 IntFontType(PFONTGDI Font)
4416 {
4417 PS_FontInfoRec psfInfo;
4418 FT_ULong tmp_size = 0;
4419 FT_Face Face = Font->SharedFace->Face;
4420
4421 if (FT_HAS_MULTIPLE_MASTERS(Face))
4422 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
4423 if (FT_HAS_VERTICAL(Face))
4424 Font->FontObj.flFontType |= FO_VERT_FACE;
4425 if (!FT_IS_SCALABLE(Face))
4426 Font->FontObj.flFontType |= FO_TYPE_RASTER;
4427 if (FT_IS_SFNT(Face))
4428 {
4429 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
4430 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
4431 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4432 }
4433 if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
4434 {
4435 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4436 }
4437 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
4438 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
4439 {
4440 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
4441 }
4442 }
4443
4444 NTSTATUS
4445 FASTCALL
4446 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
4447 {
4448 NTSTATUS Status = STATUS_SUCCESS;
4449 PTEXTOBJ TextObj;
4450 UNICODE_STRING ActualNameW, RequestedNameW;
4451 PPROCESSINFO Win32Process;
4452 ULONG MatchPenalty;
4453 LOGFONTW *pLogFont;
4454 FT_Face Face;
4455 BYTE RequestedCharSet;
4456
4457 if (!pTextObj)
4458 {
4459 TextObj = TEXTOBJ_LockText(FontHandle);
4460 if (NULL == TextObj)
4461 {
4462 return STATUS_INVALID_HANDLE;
4463 }
4464
4465 if (TextObj->fl & TEXTOBJECT_INIT)
4466 {
4467 TEXTOBJ_UnlockText(TextObj);
4468 return STATUS_SUCCESS;
4469 }
4470 }
4471 else
4472 {
4473 TextObj = pTextObj;
4474 }
4475
4476 RtlInitUnicodeString(&ActualNameW, NULL);
4477
4478 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4479 if (!RtlCreateUnicodeString(&RequestedNameW, pLogFont->lfFaceName))
4480 {
4481 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
4482 return STATUS_NO_MEMORY;
4483 }
4484
4485 /* substitute */
4486 RequestedCharSet = pLogFont->lfCharSet;
4487 DPRINT("Font '%ls,%u' is substituted by: ",
4488 RequestedNameW.Buffer, RequestedCharSet);
4489 SubstituteFontRecurse(&RequestedNameW, &RequestedCharSet);
4490 DPRINT("'%ls,%u'.\n", RequestedNameW.Buffer, RequestedCharSet);
4491
4492 MatchPenalty = 0xFFFFFFFF;
4493 TextObj->Font = NULL;
4494
4495 Win32Process = PsGetCurrentProcessWin32Process();
4496
4497 /* Search private fonts */
4498 IntLockProcessPrivateFonts(Win32Process);
4499 FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont,
4500 &RequestedNameW, &ActualNameW, RequestedCharSet,
4501 &Win32Process->PrivateFontListHead);
4502 IntUnLockProcessPrivateFonts(Win32Process);
4503
4504 /* Search system fonts */
4505 IntLockGlobalFonts;
4506 FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont,
4507 &RequestedNameW, &ActualNameW, RequestedCharSet,
4508 &FontListHead);
4509 IntUnLockGlobalFonts;
4510
4511 if (NULL == TextObj->Font)
4512 {
4513 DPRINT1("Request font %S not found, no fonts loaded at all\n",
4514 pLogFont->lfFaceName);
4515 Status = STATUS_NOT_FOUND;
4516 }
4517 else
4518 {
4519 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
4520 // Need hdev, when freetype is loaded need to create DEVOBJ for
4521 // Consumer and Producer.
4522 TextObj->Font->iUniq = 1; // Now it can be cached.
4523 IntFontType(FontGdi);
4524 FontGdi->flType = TextObj->Font->flFontType;
4525 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
4526 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
4527 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
4528 if (pLogFont->lfWeight != FW_DONTCARE)
4529 FontGdi->RequestWeight = pLogFont->lfWeight;
4530 else
4531 FontGdi->RequestWeight = FW_NORMAL;
4532
4533 Face = FontGdi->SharedFace->Face;
4534
4535 //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name);
4536
4537 if (!FontGdi->OriginalItalic)
4538 FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name);
4539
4540 TextObj->fl |= TEXTOBJECT_INIT;
4541 Status = STATUS_SUCCESS;
4542
4543 DPRINT("RequestedNameW: %ls (CharSet: %d) -> ActualNameW: %ls (CharSet: %d)\n",
4544 RequestedNameW.Buffer, pLogFont->lfCharSet,
4545 ActualNameW.Buffer, FontGdi->CharSet);
4546 }
4547
4548 RtlFreeUnicodeString(&RequestedNameW);
4549 RtlFreeUnicodeString(&ActualNameW);
4550 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
4551
4552 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
4553
4554 return Status;
4555 }
4556
4557
4558 static
4559 BOOL
4560 FASTCALL
4561 IntGetFullFileName(
4562 POBJECT_NAME_INFORMATION NameInfo,
4563 ULONG Size,
4564 PUNICODE_STRING FileName)
4565 {
4566 NTSTATUS Status;
4567 OBJECT_ATTRIBUTES ObjectAttributes;
4568 HANDLE hFile;
4569 IO_STATUS_BLOCK IoStatusBlock;
4570 ULONG Desired;
4571
4572 InitializeObjectAttributes(&ObjectAttributes,
4573 FileName,
4574 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
4575 NULL,
4576 NULL);
4577
4578 Status = ZwOpenFile(
4579 &hFile,
4580 0, // FILE_READ_ATTRIBUTES,
4581 &ObjectAttributes,
4582 &IoStatusBlock,
4583 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4584 0);
4585
4586 if (!NT_SUCCESS(Status))
4587 {
4588 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
4589 return FALSE;
4590 }
4591
4592 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
4593 ZwClose(hFile);
4594 if (!NT_SUCCESS(Status))
4595 {
4596 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
4597 return FALSE;
4598 }
4599
4600 return TRUE;
4601 }
4602
4603 static BOOL
4604 EqualFamilyInfo(FONTFAMILYINFO *pInfo1, FONTFAMILYINFO *pInfo2)
4605 {
4606 UNICODE_STRING Str1, Str2;
4607 ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
4608 ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
4609 RtlInitUnicodeString(&Str1, pLog1->elfLogFont.lfFaceName);
4610 RtlInitUnicodeString(&Str2, pLog2->elfLogFont.lfFaceName);
4611 if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE))
4612 {
4613 return FALSE;
4614 }
4615 if ((pLog1->elfStyle != NULL) != (pLog2->elfStyle != NULL))
4616 return FALSE;
4617 if (pLog1->elfStyle != NULL)
4618 {
4619 RtlInitUnicodeString(&Str1, pLog1->elfStyle);
4620 RtlInitUnicodeString(&Str2, pLog2->elfStyle);
4621 if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE))
4622 {
4623 return FALSE;
4624 }
4625 }
4626 return TRUE;
4627 }
4628
4629 static VOID
4630 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
4631 {
4632 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
4633 if (FamInfo->EnumLogFontEx.elfStyle[0] &&
4634 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
4635 {
4636 wcscat(psz, L" ");
4637 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
4638 }
4639 }
4640
4641 BOOL
4642 FASTCALL
4643 IntGdiGetFontResourceInfo(
4644 PUNICODE_STRING FileName,
4645 PVOID pBuffer,
4646 DWORD *pdwBytes,
4647 DWORD dwType)
4648 {
4649 UNICODE_STRING EntryFileName;
4650 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
4651 PLIST_ENTRY ListEntry;
4652 PFONT_ENTRY FontEntry;
4653 ULONG Size, i, Count;
4654 LPBYTE pbBuffer;
4655 BOOL IsEqual;
4656 FONTFAMILYINFO *FamInfo;
4657 const ULONG MaxFamInfo = 64;
4658 BOOL bSuccess;
4659
4660 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
4661
4662 /* Create buffer for full path name */
4663 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
4664 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4665 if (!NameInfo1)
4666 {
4667 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4668 return FALSE;
4669 }
4670
4671 /* Get the full path name */
4672 if (!IntGetFullFileName(NameInfo1, Size, FileName))
4673 {
4674 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4675 return FALSE;
4676 }
4677
4678 /* Create a buffer for the entries' names */
4679 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4680 if (!NameInfo2)
4681 {
4682 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4683 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4684 return FALSE;
4685 }
4686
4687 FamInfo = ExAllocatePoolWithTag(PagedPool,
4688 sizeof(FONTFAMILYINFO) * MaxFamInfo,
4689 TAG_FINF);
4690 if (!FamInfo)
4691 {
4692 ExFreePoolWithTag(NameInfo2, TAG_FINF);
4693 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4694 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4695 return FALSE;
4696 }
4697 /* Try to find the pathname in the global font list */
4698 Count = 0;
4699 IntLockGlobalFonts;
4700 for (ListEntry = FontListHead.Flink; ListEntry != &FontListHead;
4701 ListEntry = ListEntry->Flink)
4702 {
4703 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
4704 if (FontEntry->Font->Filename == NULL)
4705 continue;
4706
4707 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
4708 if (!IntGetFullFileName(NameInfo2, Size, &EntryFileName))
4709 continue;
4710
4711 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
4712 continue;
4713
4714 IsEqual = FALSE;
4715 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
4716 FontEntry->Font);
4717 for (i = 0; i < Count; ++i)
4718 {
4719 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
4720 {
4721 IsEqual = TRUE;
4722 break;
4723 }
4724 }
4725 if (!IsEqual)
4726 {
4727 /* Found */
4728 ++Count;
4729 if (Count >= MaxFamInfo)
4730 break;
4731 }
4732 }
4733 IntUnLockGlobalFonts;
4734
4735 /* Free the buffers */
4736 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4737 ExFreePool(NameInfo2);
4738
4739 if (Count == 0 && dwType != 5)
4740 {
4741 /* Font could not be found in system table
4742 dwType == 5 will still handle this */
4743 ExFreePoolWithTag(FamInfo, TAG_FINF);
4744 return FALSE;
4745 }
4746
4747 bSuccess = FALSE;
4748 switch (dwType)
4749 {
4750 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
4751 Size = sizeof(DWORD);
4752 if (*pdwBytes == 0)
4753 {
4754 *pdwBytes = Size;
4755 bSuccess = TRUE;
4756 }
4757 else if (pBuffer)
4758 {
4759 if (*pdwBytes >= Size)
4760 {
4761 *(DWORD*)pBuffer = Count;
4762 }
4763 *pdwBytes = Size;
4764 bSuccess = TRUE;
4765 }
4766 break;
4767
4768 case 1: /* copy the font title */
4769 /* calculate the required size */
4770 Size = 0;
4771 Size += wcslen(FamInfo[0].EnumLogFontEx.elfLogFont.lfFaceName);
4772 if (FamInfo[0].EnumLogFontEx.elfStyle[0] &&
4773 _wcsicmp(FamInfo[0].EnumLogFontEx.elfStyle, L"Regular") != 0)
4774 {
4775 Size += 1 + wcslen(FamInfo[0].EnumLogFontEx.elfStyle);
4776 }
4777 for (i = 1; i < Count; ++i)
4778 {
4779 Size += 3; /* " & " */
4780 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
4781 if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
4782 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
4783 {
4784 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
4785 }
4786 }
4787 Size += 2; /* "\0\0" */
4788 Size *= sizeof(WCHAR);
4789
4790 if (*pdwBytes == 0)
4791 {
4792 *pdwBytes = Size;
4793 bSuccess = TRUE;
4794 }
4795 else if (pBuffer)
4796 {
4797 if (*pdwBytes >= Size)
4798 {
4799 /* store font title to buffer */
4800 WCHAR *psz = pBuffer;
4801 *psz = 0;
4802 IntAddNameFromFamInfo(psz, &FamInfo[0]);
4803 for (i = 1; i < Count; ++i)
4804 {
4805 wcscat(psz, L" & ");
4806 IntAddNameFromFamInfo(psz, &FamInfo[i]);
4807 }
4808 psz[wcslen(psz) + 1] = UNICODE_NULL;
4809 *pdwBytes = Size;
4810 bSuccess = TRUE;
4811 }
4812 else
4813 {
4814 *pdwBytes = 1024; /* this is confirmed value */
4815 }
4816 }
4817 break;
4818
4819 case 2: /* Copy an array of LOGFONTW */
4820 Size = Count * sizeof(LOGFONTW);
4821 if (*pdwBytes == 0)
4822 {
4823 *pdwBytes = Size;
4824 bSuccess = TRUE;
4825 }
4826 else if (pBuffer)
4827 {
4828 if (*pdwBytes >= Size)
4829 {
4830 pbBuffer = (LPBYTE)pBuffer;
4831 for (i = 0; i < Count; ++i)
4832 {
4833 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
4834 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
4835 pbBuffer += sizeof(LOGFONTW);
4836 }
4837 }
4838 *pdwBytes = Size;
4839 bSuccess = TRUE;
4840 }
4841 else
4842 {
4843 *pdwBytes = 1024; /* this is confirmed value */
4844 }
4845 break;
4846
4847 case 3:
4848 Size = sizeof(DWORD);
4849 if (*pdwBytes == 0)
4850 {
4851 *pdwBytes = Size;
4852 bSuccess = TRUE;
4853 }
4854 else if (pBuffer)
4855 {
4856 if (*pdwBytes >= Size)
4857 {
4858 /* FIXME: What exactly is copied here? */
4859 *(DWORD*)pBuffer = 1;
4860 }
4861 *pdwBytes = Size;
4862 bSuccess = TRUE;
4863 }
4864 break;
4865
4866 case 4: /* full file path */
4867 if (FileName->Length >= 4 * sizeof(WCHAR))
4868 {
4869 /* The beginning of FileName is \??\ */
4870 LPWSTR pch = FileName->Buffer + 4;
4871 DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
4872
4873 Size = Length + sizeof(WCHAR);
4874 if (*pdwBytes == 0)
4875 {
4876 *pdwBytes = Size;
4877 bSuccess = TRUE;
4878 }
4879 else if (pBuffer)
4880 {
4881 if (*pdwBytes >= Size)
4882 {
4883 RtlCopyMemory(pBuffer, pch, Size);
4884 }
4885 *pdwBytes = Size;
4886 bSuccess = TRUE;
4887 }
4888 }
4889 break;
4890
4891 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
4892 Size = sizeof(BOOL);
4893 if (*pdwBytes == 0)
4894 {
4895 *pdwBytes = Size;
4896 bSuccess = TRUE;
4897 }
4898 else if (pBuffer)
4899 {
4900 if (*pdwBytes >= Size)
4901 {
4902 *(BOOL*)pBuffer = Count == 0;
4903 }
4904 *pdwBytes = Size;
4905 bSuccess = TRUE;
4906 }
4907 break;
4908 }
4909 ExFreePoolWithTag(FamInfo, TAG_FINF);
4910
4911 return bSuccess;
4912 }
4913
4914
4915 BOOL
4916 FASTCALL
4917 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
4918 {
4919 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
4920 Info->iTechnology = RI_TECH_BITMAP;
4921 else
4922 {
4923 if (FT_IS_SCALABLE(Font->SharedFace->Face))
4924 Info->iTechnology = RI_TECH_SCALABLE;
4925 else
4926 Info->iTechnology = RI_TECH_FIXED;
4927 }
4928 Info->iUniq = Font->FontObj.iUniq;
4929 Info->dwUnknown = -1;
4930 return TRUE;
4931 }
4932
4933
4934 DWORD
4935 FASTCALL
4936 ftGdiGetKerningPairs( PFONTGDI Font,
4937 DWORD cPairs,
4938 LPKERNINGPAIR pKerningPair)
4939 {
4940 DWORD Count = 0;
4941 INT i = 0;
4942 FT_Face face = Font->SharedFace->Face;
4943
4944 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
4945 {
4946 FT_UInt previous_index = 0, glyph_index = 0;
4947 FT_ULong char_code, char_previous;
4948 FT_Vector delta;
4949
4950 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
4951
4952 IntLockFreeType;
4953
4954 while (glyph_index)
4955 {
4956 if (previous_index && glyph_index)
4957 {
4958 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
4959
4960 if (pKerningPair && cPairs)
4961 {
4962 pKerningPair[i].wFirst = char_previous;
4963 pKerningPair[i].wSecond = char_code;
4964 pKerningPair[i].iKernAmount = delta.x;
4965 i++;
4966 if (i == cPairs) break;
4967 }
4968 Count++;
4969 }
4970 previous_index = glyph_index;
4971 char_previous = char_code;
4972 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
4973 }
4974 IntUnLockFreeType;
4975 }
4976 return Count;
4977 }
4978
4979
4980 ///////////////////////////////////////////////////////////////////////////
4981 //
4982 // Functions needing sorting.
4983 //
4984 ///////////////////////////////////////////////////////////////////////////
4985 int APIENTRY
4986 NtGdiGetFontFamilyInfo(HDC Dc,
4987 LPLOGFONTW UnsafeLogFont,
4988 PFONTFAMILYINFO UnsafeInfo,
4989 DWORD Size)
4990 {
4991 NTSTATUS Status;
4992 LOGFONTW LogFont;
4993 PFONTFAMILYINFO Info;
4994 DWORD Count;
4995 PPROCESSINFO Win32Process;
4996
4997 /* Make a safe copy */
4998 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
4999 if (! NT_SUCCESS(Status))
5000 {
5001 EngSetLastError(ERROR_INVALID_PARAMETER);
5002 return -1;
5003 }
5004
5005 /* Allocate space for a safe copy */
5006 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT);
5007 if (NULL == Info)
5008 {
5009 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5010 return -1;
5011 }
5012
5013 /* Enumerate font families in the global list */
5014 IntLockGlobalFonts;
5015 Count = 0;
5016 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
5017 {
5018 IntUnLockGlobalFonts;
5019 ExFreePoolWithTag(Info, GDITAG_TEXT);
5020 return -1;
5021 }
5022 IntUnLockGlobalFonts;
5023
5024 /* Enumerate font families in the process local list */
5025 Win32Process = PsGetCurrentProcessWin32Process();
5026 IntLockProcessPrivateFonts(Win32Process);
5027 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
5028 &Win32Process->PrivateFontListHead))
5029 {
5030 IntUnLockProcessPrivateFonts(Win32Process);
5031 ExFreePoolWithTag(Info, GDITAG_TEXT);
5032 return -1;
5033 }
5034 IntUnLockProcessPrivateFonts(Win32Process);
5035
5036 /* Enumerate font families in the registry */
5037 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
5038 {
5039 ExFreePoolWithTag(Info, GDITAG_TEXT);
5040 return -1;
5041 }
5042
5043 /* Return data to caller */
5044 if (0 != Count)
5045 {
5046 Status = MmCopyToCaller(UnsafeInfo, Info,
5047 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
5048 if (! NT_SUCCESS(Status))
5049 {
5050 ExFreePoolWithTag(Info, GDITAG_TEXT);
5051 EngSetLastError(ERROR_INVALID_PARAMETER);
5052 return -1;
5053 }
5054 }
5055
5056 ExFreePoolWithTag(Info, GDITAG_TEXT);
5057
5058 return Count;
5059 }
5060
5061 FORCEINLINE
5062 LONG
5063 ScaleLong(LONG lValue, PFLOATOBJ pef)
5064 {
5065 FLOATOBJ efTemp;
5066
5067 /* Check if we have scaling different from 1 */
5068 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
5069 {
5070 /* Need to multiply */
5071 FLOATOBJ_SetLong(&efTemp, lValue);
5072 FLOATOBJ_Mul(&efTemp, pef);
5073 lValue = FLOATOBJ_GetLong(&efTemp);
5074 }
5075
5076 return lValue;
5077 }
5078
5079 BOOL
5080 APIENTRY
5081 GreExtTextOutW(
5082 IN HDC hDC,
5083 IN INT XStart,
5084 IN INT YStart,
5085 IN UINT fuOptions,
5086 IN OPTIONAL PRECTL lprc,
5087 IN LPCWSTR String,
5088 IN INT Count,
5089 IN OPTIONAL LPINT Dx,
5090 IN DWORD dwCodePage)
5091 {
5092 /*
5093 * FIXME:
5094 * Call EngTextOut, which does the real work (calling DrvTextOut where
5095 * appropriate)
5096 */
5097
5098 DC *dc;
5099 PDC_ATTR pdcattr;
5100 SURFOBJ *SurfObj;
5101 SURFACE *psurf = NULL;
5102 int error, glyph_index, i;
5103 FT_Face face;
5104 FT_GlyphSlot glyph;
5105 FT_BitmapGlyph realglyph;
5106 LONGLONG TextLeft, RealXStart;
5107 ULONG TextTop, previous, BackgroundLeft;
5108 FT_Bool use_kerning;
5109 RECTL DestRect, MaskRect;
5110 POINTL SourcePoint, BrushOrigin;
5111 HBITMAP HSourceGlyph;
5112 SURFOBJ *SourceGlyphSurf;
5113 SIZEL bitSize;
5114 INT yoff;
5115 FONTOBJ *FontObj;
5116 PFONTGDI FontGDI;
5117 PTEXTOBJ TextObj = NULL;
5118 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
5119 FT_Render_Mode RenderMode;
5120 BOOLEAN Render;
5121 POINT Start;
5122 BOOL DoBreak = FALSE;
5123 USHORT DxShift;
5124 PMATRIX pmxWorldToDevice;
5125 LONG fixAscender, fixDescender;
5126 FLOATOBJ Scale;
5127 LOGFONTW *plf;
5128 BOOL EmuBold, EmuItalic;
5129 int thickness;
5130
5131 // TODO: Write test-cases to exactly match real Windows in different
5132 // bad parameters (e.g. does Windows check the DC or the RECT first?).
5133 dc = DC_LockDc(hDC);
5134 if (!dc)
5135 {
5136 EngSetLastError(ERROR_INVALID_HANDLE);
5137 return FALSE;
5138 }
5139 if (dc->dctype == DC_TYPE_INFO)
5140 {
5141 DC_UnlockDc(dc);
5142 /* Yes, Windows really returns TRUE in this case */
5143 return TRUE;
5144 }
5145
5146 pdcattr = dc->pdcattr;
5147
5148 if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE)
5149 {
5150 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5151 DC_vUpdateBackgroundBrush(dc);
5152 }
5153
5154 /* Check if String is valid */
5155 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
5156 {
5157 EngSetLastError(ERROR_INVALID_PARAMETER);
5158 goto fail;
5159 }
5160
5161 DxShift = fuOptions & ETO_PDY ? 1 : 0;
5162
5163 if (PATH_IsPathOpen(dc->dclevel))
5164 {
5165 if (!PATH_ExtTextOut( dc,
5166 XStart,
5167 YStart,
5168 fuOptions,
5169 (const RECTL *)lprc,
5170 String,
5171 Count,
5172 (const INT *)Dx)) goto fail;
5173 goto good;
5174 }
5175
5176 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
5177 {
5178 IntLPtoDP(dc, (POINT *)lprc, 2);
5179 }
5180
5181 if (pdcattr->lTextAlign & TA_UPDATECP)
5182 {
5183 Start.x = pdcattr->ptlCurrent.x;
5184 Start.y = pdcattr->ptlCurrent.y;
5185 } else {
5186 Start.x = XStart;
5187 Start.y = YStart;
5188 }
5189
5190 IntLPtoDP(dc, &Start, 1);
5191 RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
5192 YStart = Start.y + dc->ptlDCOrig.y;
5193
5194 SourcePoint.x = 0;
5195 SourcePoint.y = 0;
5196 MaskRect.left = 0;
5197 MaskRect.top = 0;
5198 BrushOrigin.x = 0;
5199 BrushOrigin.y = 0;
5200
5201 if (!dc->dclevel.pSurface)
5202 {
5203 goto fail;
5204 }
5205
5206 if ((fuOptions & ETO_OPAQUE) && lprc)
5207 {
5208 DestRect.left = lprc->left;
5209 DestRect.top = lprc->top;
5210 DestRect.right = lprc->right;
5211 DestRect.bottom = lprc->bottom;
5212
5213 DestRect.left += dc->ptlDCOrig.x;
5214 DestRect.top += dc->ptlDCOrig.y;
5215 DestRect.right += dc->ptlDCOrig.x;
5216 DestRect.bottom += dc->ptlDCOrig.y;
5217
5218 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5219 {
5220 IntUpdateBoundsRect(dc, &DestRect);
5221 }
5222
5223 DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL);
5224
5225 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5226 DC_vUpdateBackgroundBrush(dc);
5227
5228 psurf = dc->dclevel.pSurface;
5229 IntEngBitBlt(
5230 &psurf->SurfObj,
5231 NULL,
5232 NULL,
5233 &dc->co.ClipObj,
5234 NULL,
5235 &DestRect,
5236 &SourcePoint,
5237 &SourcePoint,
5238 &dc->eboBackground.BrushObject,
5239 &BrushOrigin,
5240 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5241 fuOptions &= ~ETO_OPAQUE;
5242 DC_vFinishBlit(dc, NULL);
5243 }
5244 else
5245 {
5246 if (pdcattr->jBkMode == OPAQUE)
5247 {
5248 fuOptions |= ETO_OPAQUE;
5249 }
5250 }
5251
5252 TextObj = RealizeFontInit(pdcattr->hlfntNew);
5253 if (TextObj == NULL)
5254 {
5255 goto fail;
5256 }
5257
5258 FontObj = TextObj->Font;
5259 ASSERT(FontObj);
5260 FontGDI = ObjToGDI(FontObj, FONT);
5261 ASSERT(FontGDI);
5262
5263 IntLockFreeType;
5264 face = FontGDI->SharedFace->Face;
5265
5266 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5267 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
5268 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
5269
5270 Render = IntIsFontRenderingEnabled();
5271 if (Render)
5272 RenderMode = IntGetFontRenderMode(plf);
5273 else
5274 RenderMode = FT_RENDER_MODE_MONO;
5275
5276 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
5277 {
5278 IntUnLockFreeType;
5279 goto fail;
5280 }
5281
5282 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
5283 {
5284 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
5285 FtSetCoordinateTransform(face, pmxWorldToDevice);
5286
5287 fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
5288 fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
5289 }
5290 else
5291 {
5292 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
5293 FtSetCoordinateTransform(face, pmxWorldToDevice);
5294
5295 fixAscender = face->size->metrics.ascender;
5296 fixDescender = face->size->metrics.descender;
5297 }
5298
5299 /*
5300 * Process the vertical alignment and determine the yoff.
5301 */
5302
5303 if (pdcattr->lTextAlign & TA_BASELINE)
5304 yoff = 0;
5305 else if (pdcattr->lTextAlign & TA_BOTTOM)
5306 yoff = -fixDescender >> 6;
5307 else /* TA_TOP */
5308 yoff = fixAscender >> 6;
5309
5310 use_kerning = FT_HAS_KERNING(face);
5311 previous = 0;
5312
5313 /*
5314 * Process the horizontal alignment and modify XStart accordingly.
5315 */
5316
5317 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
5318 {
5319 ULONGLONG TextWidth = 0;
5320 LPCWSTR TempText = String;
5321 int iStart;
5322
5323 /*
5324 * Calculate width of the text.
5325 */
5326
5327 if (NULL != Dx)
5328 {
5329 iStart = Count < 2 ? 0 : Count - 2;
5330 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
5331 }
5332 else
5333 {
5334 iStart = 0;
5335 }
5336 TempText = String + iStart;
5337
5338 for (i = iStart; i < Count; i++)
5339 {
5340 if (fuOptions & ETO_GLYPH_INDEX)
5341 glyph_index = *TempText;
5342 else
5343 glyph_index = FT_Get_Char_Index(face, *TempText);
5344
5345 if (EmuBold || EmuItalic)
5346 realglyph = NULL;
5347 else
5348 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
5349 plf->lfHeight, pmxWorldToDevice);
5350 if (!realglyph)
5351 {
5352 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5353 if (error)
5354 {
5355 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
5356 }
5357
5358 glyph = face->glyph;
5359 if (EmuBold || EmuItalic)
5360 {
5361 if (EmuBold)
5362 FT_GlyphSlot_Embolden(glyph);
5363 if (EmuItalic)
5364 FT_GlyphSlot_Oblique(glyph);
5365 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5366 }
5367 else
5368 {
5369 realglyph = ftGdiGlyphCacheSet(face,
5370 glyph_index,
5371 plf->lfHeight,
5372 pmxWorldToDevice,
5373 glyph,
5374 RenderMode);
5375 }
5376 if (!realglyph)
5377 {
5378 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5379 IntUnLockFreeType;
5380 goto fail;
5381 }
5382
5383 }
5384 /* Retrieve kerning distance */
5385 if (use_kerning && previous && glyph_index)
5386 {
5387 FT_Vector delta;
5388 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5389 TextWidth += delta.x;
5390 }
5391
5392 TextWidth += realglyph->root.advance.x >> 10;
5393
5394 if (EmuBold || EmuItalic)
5395 {
5396 FT_Done_Glyph((FT_Glyph)realglyph);
5397 realglyph = NULL;
5398 }
5399
5400 previous = glyph_index;
5401 TempText++;
5402 }
5403
5404 previous = 0;
5405
5406 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
5407 {
5408 RealXStart -= TextWidth / 2;
5409 }
5410 else
5411 {
5412 RealXStart -= TextWidth;
5413 }
5414 }
5415
5416 /* Lock blit with a dummy rect */
5417 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
5418
5419 psurf = dc->dclevel.pSurface;
5420 SurfObj = &psurf->SurfObj ;
5421
5422 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
5423 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
5424
5425 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
5426 DC_vUpdateBackgroundBrush(dc) ;
5427
5428 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
5429 DC_vUpdateTextBrush(dc) ;
5430
5431 if (!face->units_per_EM)
5432 {
5433 thickness = 1;
5434 }
5435 else
5436 {
5437 thickness = face->underline_thickness *
5438 face->size->metrics.y_ppem / face->units_per_EM;
5439 if (thickness <= 0)
5440 thickness = 1;
5441 }
5442
5443 if ((fuOptions & ETO_OPAQUE) && plf->lfItalic)
5444 {
5445 /* Draw background */
5446 TextLeft = RealXStart;
5447 TextTop = YStart;
5448 BackgroundLeft = (RealXStart + 32) >> 6;
5449 for (i = 0; i < Count; ++i)
5450 {
5451 if (fuOptions & ETO_GLYPH_INDEX)
5452 glyph_index = String[i];
5453 else
5454 glyph_index = FT_Get_Char_Index(face, String[i]);
5455
5456 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5457 if (error)
5458 {
5459 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5460 IntUnLockFreeType;
5461 DC_vFinishBlit(dc, NULL);
5462 goto fail2;
5463 }
5464
5465 glyph = face->glyph;
5466 if (EmuBold)
5467 FT_GlyphSlot_Embolden(glyph);
5468 if (EmuItalic)
5469 FT_GlyphSlot_Oblique(glyph);
5470 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5471 if (!realglyph)
5472 {
5473 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5474 IntUnLockFreeType;
5475 DC_vFinishBlit(dc, NULL);
5476 goto fail2;
5477 }
5478
5479 /* retrieve kerning distance and move pen position */
5480 if (use_kerning && previous && glyph_index && NULL == Dx)
5481 {
5482 FT_Vector delta;
5483 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5484 TextLeft += delta.x;
5485 }
5486 DPRINT("TextLeft: %I64d\n", TextLeft);
5487 DPRINT("TextTop: %lu\n", TextTop);
5488 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5489
5490 DestRect.left = BackgroundLeft;
5491 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5492 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5493 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5494 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5495 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5496 {
5497 IntUpdateBoundsRect(dc, &DestRect);
5498 }
5499 IntEngBitBlt(
5500 &psurf->SurfObj,
5501 NULL,
5502 NULL,
5503 &dc->co.ClipObj,
5504 NULL,
5505 &DestRect,
5506 &SourcePoint,
5507 &SourcePoint,
5508 &dc->eboBackground.BrushObject,
5509 &BrushOrigin,
5510 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5511 MouseSafetyOnDrawEnd(dc->ppdev);
5512 BackgroundLeft = DestRect.right;
5513
5514 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5515 DestRect.right = DestRect.left + realglyph->bitmap.width;
5516 DestRect.top = TextTop + yoff - realglyph->top;
5517 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5518
5519 bitSize.cx = realglyph->bitmap.width;
5520 bitSize.cy = realglyph->bitmap.rows;
5521 MaskRect.right = realglyph->bitmap.width;
5522 MaskRect.bottom = realglyph->bitmap.rows;
5523
5524 if (NULL == Dx)
5525 {
5526 TextLeft += realglyph->root.advance.x >> 10;
5527 DPRINT("New TextLeft: %I64d\n", TextLeft);
5528 }
5529 else
5530 {
5531 // FIXME this should probably be a matrix transform with TextTop as well.
5532 Scale = pdcattr->mxWorldToDevice.efM11;
5533 if (FLOATOBJ_Equal0(&Scale))
5534 FLOATOBJ_Set1(&Scale);
5535
5536 /* do the shift before multiplying to preserve precision */
5537 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5538 TextLeft += FLOATOBJ_GetLong(&Scale);
5539 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5540 }
5541
5542 if (DxShift)
5543 {
5544 TextTop -= Dx[2 * i + 1] << 6;
5545 }
5546
5547 previous = glyph_index;
5548
5549 if (EmuBold || EmuItalic)
5550 {
5551 FT_Done_Glyph((FT_Glyph)realglyph);
5552 realglyph = NULL;
5553 }
5554 }
5555 }
5556
5557 /*
5558 * The main rendering loop.
5559 */
5560 TextLeft = RealXStart;
5561 TextTop = YStart;
5562 BackgroundLeft = (RealXStart + 32) >> 6;
5563 for (i = 0; i < Count; ++i)
5564 {
5565 if (fuOptions & ETO_GLYPH_INDEX)
5566 glyph_index = String[i];
5567 else
5568 glyph_index = FT_Get_Char_Index(face, String[i]);
5569
5570 if (EmuBold || EmuItalic)
5571 realglyph = NULL;
5572 else
5573 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
5574 plf->lfHeight, pmxWorldToDevice);
5575 if (!realglyph)
5576 {
5577 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5578 if (error)
5579 {
5580 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5581 IntUnLockFreeType;
5582 DC_vFinishBlit(dc, NULL);
5583 goto fail2;
5584 }
5585
5586 glyph = face->glyph;
5587 if (EmuBold || EmuItalic)
5588 {
5589 if (EmuBold)
5590 FT_GlyphSlot_Embolden(glyph);
5591 if (EmuItalic)
5592 FT_GlyphSlot_Oblique(glyph);
5593 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5594 }
5595 else
5596 {
5597 realglyph = ftGdiGlyphCacheSet(face,
5598 glyph_index,
5599 plf->lfHeight,
5600 pmxWorldToDevice,
5601 glyph,
5602 RenderMode);
5603 }
5604 if (!realglyph)
5605 {
5606 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5607 IntUnLockFreeType;
5608 DC_vFinishBlit(dc, NULL);
5609 goto fail2;
5610 }
5611 }
5612
5613 /* retrieve kerning distance and move pen position */
5614 if (use_kerning && previous && glyph_index && NULL == Dx)
5615 {
5616 FT_Vector delta;
5617 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5618 TextLeft += delta.x;
5619 }
5620 DPRINT("TextLeft: %I64d\n", TextLeft);
5621 DPRINT("TextTop: %lu\n", TextTop);
5622 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5623
5624 if ((fuOptions & ETO_OPAQUE) && !plf->lfItalic)
5625 {
5626 DestRect.left = BackgroundLeft;
5627 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5628 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5629 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5630 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5631 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5632 {
5633 IntUpdateBoundsRect(dc, &DestRect);
5634 }
5635 IntEngBitBlt(
5636 &psurf->SurfObj,
5637 NULL,
5638 NULL,
5639 &dc->co.ClipObj,
5640 NULL,
5641 &DestRect,
5642 &SourcePoint,
5643 &SourcePoint,
5644 &dc->eboBackground.BrushObject,
5645 &BrushOrigin,
5646 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5647 MouseSafetyOnDrawEnd(dc->ppdev);
5648 BackgroundLeft = DestRect.right;
5649 }
5650
5651 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5652 DestRect.right = DestRect.left + realglyph->bitmap.width;
5653 DestRect.top = TextTop + yoff - realglyph->top;
5654 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5655
5656 bitSize.cx = realglyph->bitmap.width;
5657 bitSize.cy = realglyph->bitmap.rows;
5658 MaskRect.right = realglyph->bitmap.width;
5659 MaskRect.bottom = realglyph->bitmap.rows;
5660
5661 /* Check if the bitmap has any pixels */
5662 if ((bitSize.cx != 0) && (bitSize.cy != 0))
5663 {
5664 /*
5665 * We should create the bitmap out of the loop at the biggest possible
5666 * glyph size. Then use memset with 0 to clear it and sourcerect to
5667 * limit the work of the transbitblt.
5668 */
5669 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
5670 BMF_8BPP, BMF_TOPDOWN,
5671 realglyph->bitmap.buffer);
5672 if ( !HSourceGlyph )
5673 {
5674 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
5675 // FT_Done_Glyph(realglyph);
5676 IntUnLockFreeType;
5677 DC_vFinishBlit(dc, NULL);
5678 goto fail2;
5679 }
5680 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
5681 if ( !SourceGlyphSurf )
5682 {
5683 EngDeleteSurface((HSURF)HSourceGlyph);
5684 DPRINT1("WARNING: EngLockSurface() failed!\n");
5685 IntUnLockFreeType;
5686 DC_vFinishBlit(dc, NULL);
5687 goto fail2;
5688 }
5689
5690 /*
5691 * Use the font data as a mask to paint onto the DCs surface using a
5692 * brush.
5693 */
5694 if (lprc && (fuOptions & ETO_CLIPPED) &&
5695 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
5696 {
5697 // We do the check '>=' instead of '>' to possibly save an iteration
5698 // through this loop, since it's breaking after the drawing is done,
5699 // and x is always incremented.
5700 DestRect.right = lprc->right + dc->ptlDCOrig.x;
5701 DoBreak = TRUE;
5702 }
5703 if (lprc && (fuOptions & ETO_CLIPPED) &&
5704 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
5705 {
5706 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
5707 }
5708 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5709 if (!IntEngMaskBlt(
5710 SurfObj,
5711 SourceGlyphSurf,
5712 &dc->co.ClipObj,
5713 &exloRGB2Dst.xlo,
5714 &exloDst2RGB.xlo,
5715 &DestRect,
5716 (PPOINTL)&MaskRect,
5717 &dc->eboText.BrushObject,
5718 &BrushOrigin))
5719 {
5720 DPRINT1("Failed to MaskBlt a glyph!\n");
5721 }
5722
5723 MouseSafetyOnDrawEnd(dc->ppdev) ;
5724
5725 EngUnlockSurface(SourceGlyphSurf);
5726 EngDeleteSurface((HSURF)HSourceGlyph);
5727 }
5728
5729 if (DoBreak)
5730 {
5731 break;
5732 }
5733
5734 if (plf->lfUnderline)
5735 {
5736 int i, position;
5737 if (!face->units_per_EM)
5738 {
5739 position = 0;
5740 }
5741 else
5742 {
5743 position = face->underline_position *
5744 face->size->metrics.y_ppem / face->units_per_EM;
5745 }
5746 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5747 {
5748 EngLineTo(SurfObj,
5749 &dc->co.ClipObj,
5750 &dc->eboText.BrushObject,
5751 (TextLeft >> 6),
5752 TextTop + yoff - position + i,
5753 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5754 TextTop + yoff - position + i,
5755 NULL,
5756 ROP2_TO_MIX(R2_COPYPEN));
5757 }
5758 }
5759 if (plf->lfStrikeOut)
5760 {
5761 int i;
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 - (fixAscender >> 6) / 3 + i,
5769 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5770 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5771 NULL,
5772 ROP2_TO_MIX(R2_COPYPEN));
5773 }
5774 }
5775
5776 if (NULL == Dx)
5777 {
5778 TextLeft += realglyph->root.advance.x >> 10;
5779 DPRINT("New TextLeft: %I64d\n", TextLeft);
5780 }
5781 else
5782 {
5783 // FIXME this should probably be a matrix transform with TextTop as well.
5784 Scale = pdcattr->mxWorldToDevice.efM11;
5785 if (FLOATOBJ_Equal0(&Scale))
5786 FLOATOBJ_Set1(&Scale);
5787
5788 /* do the shift before multiplying to preserve precision */
5789 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5790 TextLeft += FLOATOBJ_GetLong(&Scale);
5791 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5792 }
5793
5794 if (DxShift)
5795 {
5796 TextTop -= Dx[2 * i + 1] << 6;
5797 }
5798
5799 previous = glyph_index;
5800
5801 if (EmuBold || EmuItalic)
5802 {
5803 FT_Done_Glyph((FT_Glyph)realglyph);
5804 realglyph = NULL;
5805 }
5806 }
5807
5808 if (pdcattr->lTextAlign & TA_UPDATECP) {
5809 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
5810 }
5811
5812 IntUnLockFreeType;
5813
5814 DC_vFinishBlit(dc, NULL) ;
5815
5816 EXLATEOBJ_vCleanup(&exloRGB2Dst);
5817 EXLATEOBJ_vCleanup(&exloDst2RGB);
5818 if (TextObj != NULL)
5819 TEXTOBJ_UnlockText(TextObj);
5820 good:
5821 DC_UnlockDc( dc );
5822
5823 return TRUE;
5824
5825 fail2:
5826 EXLATEOBJ_vCleanup(&exloRGB2Dst);
5827 EXLATEOBJ_vCleanup(&exloDst2RGB);
5828 fail:
5829 if (TextObj != NULL)
5830 TEXTOBJ_UnlockText(TextObj);
5831
5832 DC_UnlockDc(dc);
5833
5834 return FALSE;
5835 }
5836
5837 #define STACK_TEXT_BUFFER_SIZE 100
5838 BOOL
5839 APIENTRY
5840 NtGdiExtTextOutW(
5841 IN HDC hDC,
5842 IN INT XStart,
5843 IN INT YStart,
5844 IN UINT fuOptions,
5845 IN OPTIONAL LPRECT UnsafeRect,
5846 IN LPWSTR UnsafeString,
5847 IN INT Count,
5848 IN OPTIONAL LPINT UnsafeDx,
5849 IN DWORD dwCodePage)
5850 {
5851 BOOL Result = FALSE;
5852 NTSTATUS Status = STATUS_SUCCESS;
5853 RECTL SafeRect;
5854 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
5855 PVOID Buffer = LocalBuffer;
5856 LPCWSTR SafeString = NULL;
5857 LPINT SafeDx = NULL;
5858 ULONG BufSize, StringSize, DxSize = 0;
5859
5860 /* Check if String is valid */
5861 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
5862 {
5863 EngSetLastError(ERROR_INVALID_PARAMETER);
5864 return FALSE;
5865 }
5866
5867 if (Count > 0)
5868 {
5869 /* Calculate buffer size for string and Dx values */
5870 BufSize = StringSize = Count * sizeof(WCHAR);
5871 if (UnsafeDx)
5872 {
5873 /* If ETO_PDY is specified, we have pairs of INTs */
5874 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
5875 BufSize += DxSize;
5876 }
5877
5878 /* Check if our local buffer is large enough */
5879 if (BufSize > STACK_TEXT_BUFFER_SIZE)
5880 {
5881 /* It's not, allocate a temp buffer */
5882 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
5883 if (!Buffer)
5884 {
5885 return FALSE;
5886 }
5887 }
5888
5889 /* Probe and copy user mode data to the buffer */
5890 _SEH2_TRY
5891 {
5892 /* Put the Dx before the String to assure alignment of 4 */
5893 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
5894
5895 /* Probe and copy the string */
5896 ProbeForRead(UnsafeString, StringSize, 1);
5897 memcpy((PVOID)SafeString, UnsafeString, StringSize);
5898
5899 /* If we have Dx values... */
5900 if (UnsafeDx)
5901 {
5902 /* ... probe and copy them */
5903 SafeDx = Buffer;
5904 ProbeForRead(UnsafeDx, DxSize, 1);
5905 memcpy(SafeDx, UnsafeDx, DxSize);
5906 }
5907 }
5908 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5909 {
5910 Status = _SEH2_GetExceptionCode();
5911 }
5912 _SEH2_END
5913 if (!NT_SUCCESS(Status))
5914 {
5915 goto cleanup;
5916 }
5917 }
5918
5919 /* If we have a rect, copy it */
5920 if (UnsafeRect)
5921 {
5922 _SEH2_TRY
5923 {
5924 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
5925 SafeRect = *UnsafeRect;
5926 }
5927 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5928 {
5929 Status = _SEH2_GetExceptionCode();
5930 }
5931 _SEH2_END
5932 if (!NT_SUCCESS(Status))
5933 {
5934 goto cleanup;
5935 }
5936 }
5937
5938 /* Finally call the internal routine */
5939 Result = GreExtTextOutW(hDC,
5940 XStart,
5941 YStart,
5942 fuOptions,
5943 &SafeRect,
5944 SafeString,
5945 Count,
5946 SafeDx,
5947 dwCodePage);
5948
5949 cleanup:
5950 /* If we allocated a buffer, free it */
5951 if (Buffer != LocalBuffer)
5952 {
5953 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
5954 }
5955
5956 return Result;
5957 }
5958
5959
5960 /*
5961 * @implemented
5962 */
5963 BOOL
5964 APIENTRY
5965 NtGdiGetCharABCWidthsW(
5966 IN HDC hDC,
5967 IN UINT FirstChar,
5968 IN ULONG Count,
5969 IN OPTIONAL PWCHAR UnSafepwch,
5970 IN FLONG fl,
5971 OUT PVOID Buffer)
5972 {
5973 LPABC SafeBuff;
5974 LPABCFLOAT SafeBuffF = NULL;
5975 PDC dc;
5976 PDC_ATTR pdcattr;
5977 PTEXTOBJ TextObj;
5978 PFONTGDI FontGDI;
5979 FT_Face face;
5980 FT_CharMap charmap, found = NULL;
5981 UINT i, glyph_index, BufferSize;
5982 HFONT hFont = 0;
5983 NTSTATUS Status = STATUS_SUCCESS;
5984 PMATRIX pmxWorldToDevice;
5985 PWCHAR Safepwch = NULL;
5986 LOGFONTW *plf;
5987
5988 if (!Buffer)
5989 {
5990 EngSetLastError(ERROR_INVALID_PARAMETER);
5991 return FALSE;
5992 }
5993
5994 if (UnSafepwch)
5995 {
5996 UINT pwchSize = Count * sizeof(WCHAR);
5997 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
5998
5999 if(!Safepwch)
6000 {
6001 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6002 return FALSE;
6003 }
6004
6005 _SEH2_TRY
6006 {
6007 ProbeForRead(UnSafepwch, pwchSize, 1);
6008 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
6009 }
6010 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6011 {
6012 Status = _SEH2_GetExceptionCode();
6013 }
6014 _SEH2_END;
6015 }
6016
6017 if (!NT_SUCCESS(Status))
6018 {
6019 if(Safepwch)
6020 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6021
6022 EngSetLastError(Status);
6023 return FALSE;
6024 }
6025
6026 BufferSize = Count * sizeof(ABC); // Same size!
6027 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6028 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
6029 if (SafeBuff == NULL)
6030 {
6031
6032 if(Safepwch)
6033 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6034
6035 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6036 return FALSE;
6037 }
6038
6039 dc = DC_LockDc(hDC);
6040 if (dc == NULL)
6041 {
6042 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6043
6044 if(Safepwch)
6045 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6046
6047 EngSetLastError(ERROR_INVALID_HANDLE);
6048 return FALSE;
6049 }
6050 pdcattr = dc->pdcattr;
6051 hFont = pdcattr->hlfntNew;
6052 TextObj = RealizeFontInit(hFont);
6053
6054 /* Get the DC's world-to-device transformation matrix */
6055 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6056 DC_UnlockDc(dc);
6057
6058 if (TextObj == NULL)
6059 {
6060 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6061
6062 if(Safepwch)
6063 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6064
6065 EngSetLastError(ERROR_INVALID_HANDLE);
6066 return FALSE;
6067 }
6068
6069 FontGDI = ObjToGDI(TextObj->Font, FONT);
6070
6071 face = FontGDI->SharedFace->Face;
6072 if (face->charmap == NULL)
6073 {
6074 for (i = 0; i < (UINT)face->num_charmaps; i++)
6075 {
6076 charmap = face->charmaps[i];
6077 if (charmap->encoding != 0)
6078 {
6079 found = charmap;
6080 break;
6081 }
6082 }
6083
6084 if (!found)
6085 {
6086 DPRINT1("WARNING: Could not find desired charmap!\n");
6087 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6088
6089 if(Safepwch)
6090 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6091
6092 EngSetLastError(ERROR_INVALID_HANDLE);
6093 return FALSE;
6094 }
6095
6096 IntLockFreeType;
6097 FT_Set_Charmap(face, found);
6098 IntUnLockFreeType;
6099 }
6100
6101 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6102 IntLockFreeType;
6103 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
6104 FtSetCoordinateTransform(face, pmxWorldToDevice);
6105
6106 for (i = FirstChar; i < FirstChar+Count; i++)
6107 {
6108 int adv, lsb, bbx, left, right;
6109
6110 if (Safepwch)
6111 {
6112 if (fl & GCABCW_INDICES)
6113 glyph_index = Safepwch[i - FirstChar];
6114 else
6115 glyph_index = FT_Get_Char_Index(face, Safepwch[i - FirstChar]);
6116 }
6117 else
6118 {
6119 if (fl & GCABCW_INDICES)
6120 glyph_index = i;
6121 else
6122 glyph_index = FT_Get_Char_Index(face, i);
6123 }
6124 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6125
6126 left = (INT)face->glyph->metrics.horiBearingX & -64;
6127 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
6128 adv = (face->glyph->advance.x + 32) >> 6;
6129
6130 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
6131 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
6132
6133 lsb = left >> 6;
6134 bbx = (right - left) >> 6;
6135 /*
6136 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
6137 */
6138 if (!fl)
6139 {
6140 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
6141 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
6142 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
6143 }
6144 else
6145 {
6146 SafeBuff[i - FirstChar].abcA = lsb;
6147 SafeBuff[i - FirstChar].abcB = bbx;
6148 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
6149 }
6150 }
6151 IntUnLockFreeType;
6152 TEXTOBJ_UnlockText(TextObj);
6153 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6154
6155 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6156
6157 if(Safepwch)
6158 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6159
6160 if (! NT_SUCCESS(Status))
6161 {
6162 SetLastNtError(Status);
6163 return FALSE;
6164 }
6165
6166 DPRINT("NtGdiGetCharABCWidths Worked!\n");
6167 return TRUE;
6168 }
6169
6170 /*
6171 * @implemented
6172 */
6173 BOOL
6174 APIENTRY
6175 NtGdiGetCharWidthW(
6176 IN HDC hDC,
6177 IN UINT FirstChar,
6178 IN UINT Count,
6179 IN OPTIONAL PWCHAR UnSafepwc,
6180 IN FLONG fl,
6181 OUT PVOID Buffer)
6182 {
6183 NTSTATUS Status = STATUS_SUCCESS;
6184 LPINT SafeBuff;
6185 PFLOAT SafeBuffF = NULL;
6186 PDC dc;
6187 PDC_ATTR pdcattr;
6188 PTEXTOBJ TextObj;
6189 PFONTGDI FontGDI;
6190 FT_Face face;
6191 FT_CharMap charmap, found = NULL;
6192 UINT i, glyph_index, BufferSize;
6193 HFONT hFont = 0;
6194 PMATRIX pmxWorldToDevice;
6195 PWCHAR Safepwc = NULL;
6196 LOGFONTW *plf;
6197
6198 if (UnSafepwc)
6199 {
6200 UINT pwcSize = Count * sizeof(WCHAR);
6201 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6202
6203 if(!Safepwc)
6204 {
6205 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6206 return FALSE;
6207 }
6208 _SEH2_TRY
6209 {
6210 ProbeForRead(UnSafepwc, pwcSize, 1);
6211 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6212 }
6213 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6214 {
6215 Status = _SEH2_GetExceptionCode();
6216 }
6217 _SEH2_END;
6218 }
6219
6220 if (!NT_SUCCESS(Status))
6221 {
6222 EngSetLastError(Status);
6223 return FALSE;
6224 }
6225
6226 BufferSize = Count * sizeof(INT); // Same size!
6227 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6228 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
6229 if (SafeBuff == NULL)
6230 {
6231 if(Safepwc)
6232 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6233
6234 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6235 return FALSE;
6236 }
6237
6238 dc = DC_LockDc(hDC);
6239 if (dc == NULL)
6240 {
6241 if(Safepwc)
6242 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6243
6244 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6245 EngSetLastError(ERROR_INVALID_HANDLE);
6246 return FALSE;
6247 }
6248 pdcattr = dc->pdcattr;
6249 hFont = pdcattr->hlfntNew;
6250 TextObj = RealizeFontInit(hFont);
6251 /* Get the DC's world-to-device transformation matrix */
6252 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6253 DC_UnlockDc(dc);
6254
6255 if (TextObj == 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
6265 FontGDI = ObjToGDI(TextObj->Font, FONT);
6266
6267 face = FontGDI->SharedFace->Face;
6268 if (face->charmap == NULL)
6269 {
6270 for (i = 0; i < (UINT)face->num_charmaps; i++)
6271 {
6272 charmap = face->charmaps[i];
6273 if (charmap->encoding != 0)
6274 {
6275 found = charmap;
6276 break;
6277 }
6278 }
6279
6280 if (!found)
6281 {
6282 DPRINT1("WARNING: Could not find desired charmap!\n");
6283
6284 if(Safepwc)
6285 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6286
6287 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6288 EngSetLastError(ERROR_INVALID_HANDLE);
6289 return FALSE;
6290 }
6291
6292 IntLockFreeType;
6293 FT_Set_Charmap(face, found);
6294 IntUnLockFreeType;
6295 }
6296
6297 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6298 IntLockFreeType;
6299 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
6300 FtSetCoordinateTransform(face, pmxWorldToDevice);
6301
6302 for (i = FirstChar; i < FirstChar+Count; i++)
6303 {
6304 if (Safepwc)
6305 {
6306 if (fl & GCW_INDICES)
6307 glyph_index = Safepwc[i - FirstChar];
6308 else
6309 glyph_index = FT_Get_Char_Index(face, Safepwc[i - FirstChar]);
6310 }
6311 else
6312 {
6313 if (fl & GCW_INDICES)
6314 glyph_index = i;
6315 else
6316 glyph_index = FT_Get_Char_Index(face, i);
6317 }
6318 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6319 if (!fl)
6320 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
6321 else
6322 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
6323 }
6324 IntUnLockFreeType;
6325 TEXTOBJ_UnlockText(TextObj);
6326 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6327
6328 if(Safepwc)
6329 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6330
6331 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6332 return TRUE;
6333 }
6334
6335
6336 /*
6337 * @implemented
6338 */
6339 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
6340 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
6341 // NOTE: See also GreGetGlyphIndicesW.
6342 __kernel_entry
6343 W32KAPI
6344 DWORD
6345 APIENTRY
6346 NtGdiGetGlyphIndicesW(
6347 _In_ HDC hdc,
6348 _In_reads_opt_(cwc) LPCWSTR pwc,
6349 _In_ INT cwc,
6350 _Out_writes_opt_(cwc) LPWORD pgi,
6351 _In_ DWORD iMode)
6352 {
6353 PDC dc;
6354 PDC_ATTR pdcattr;
6355 PTEXTOBJ TextObj;
6356 PFONTGDI FontGDI;
6357 HFONT hFont = NULL;
6358 NTSTATUS Status = STATUS_SUCCESS;
6359 OUTLINETEXTMETRICW *potm;
6360 INT i;
6361 WCHAR DefChar = 0xffff;
6362 PWSTR Buffer = NULL;
6363 ULONG Size, pwcSize;
6364 PWSTR Safepwc = NULL;
6365 LPCWSTR UnSafepwc = pwc;
6366 LPWORD UnSafepgi = pgi;
6367
6368 /* Check for integer overflow */
6369 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN
6370 return GDI_ERROR;
6371
6372 if (!UnSafepwc && !UnSafepgi)
6373 return cwc;
6374
6375 if (!UnSafepwc || !UnSafepgi)
6376 {
6377 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
6378 return GDI_ERROR;
6379 }
6380
6381 // TODO: Special undocumented case!
6382 if (!pwc && !pgi && (cwc == 0))
6383 {
6384 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n");
6385 return 0;
6386 }
6387
6388 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825
6389 if (cwc == 0)
6390 {
6391 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n");
6392 return GDI_ERROR;
6393 }
6394
6395 dc = DC_LockDc(hdc);
6396 if (!dc)
6397 {
6398 return GDI_ERROR;
6399 }
6400 pdcattr = dc->pdcattr;
6401 hFont = pdcattr->hlfntNew;
6402 TextObj = RealizeFontInit(hFont);
6403 DC_UnlockDc(dc);
6404 if (!TextObj)
6405 {
6406 return GDI_ERROR;
6407 }
6408
6409 FontGDI = ObjToGDI(TextObj->Font, FONT);
6410 TEXTOBJ_UnlockText(TextObj);
6411
6412 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
6413 if (!Buffer)
6414 {
6415 return GDI_ERROR;
6416 }
6417
6418 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
6419 {
6420 DefChar = 0xffff;
6421 }
6422 else
6423 {
6424 FT_Face Face = FontGDI->SharedFace->Face;
6425 if (FT_IS_SFNT(Face))
6426 {
6427 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
6428 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(Face, pOS2->usDefaultChar) : 0);
6429 }
6430 else
6431 {
6432 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
6433 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
6434 if (!potm)
6435 {
6436 cwc = GDI_ERROR;
6437 goto ErrorRet;
6438 }
6439 IntGetOutlineTextMetrics(FontGDI, Size, potm);
6440 DefChar = potm->otmTextMetrics.tmDefaultChar;
6441 ExFreePoolWithTag(potm, GDITAG_TEXT);
6442 }
6443 }
6444
6445 pwcSize = cwc * sizeof(WCHAR);
6446 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6447
6448 if (!Safepwc)
6449 {
6450 Status = STATUS_NO_MEMORY;
6451 goto ErrorRet;
6452 }
6453
6454 _SEH2_TRY
6455 {
6456 ProbeForRead(UnSafepwc, pwcSize, 1);
6457 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6458 }
6459 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6460 {
6461 Status = _SEH2_GetExceptionCode();
6462 }
6463 _SEH2_END;
6464
6465 if (!NT_SUCCESS(Status)) goto ErrorRet;
6466
6467 IntLockFreeType;
6468
6469 for (i = 0; i < cwc; i++)
6470 {
6471 Buffer[i] = FT_Get_Char_Index(FontGDI->SharedFace->Face, Safepwc[i]);
6472 if (Buffer[i] == 0)
6473 {
6474 Buffer[i] = DefChar;
6475 }
6476 }
6477
6478 IntUnLockFreeType;
6479
6480 _SEH2_TRY
6481 {
6482 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
6483 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
6484 }
6485 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6486 {
6487 Status = _SEH2_GetExceptionCode();
6488 }
6489 _SEH2_END;
6490
6491 ErrorRet:
6492 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6493 if (Safepwc != NULL)
6494 {
6495 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6496 }
6497 if (NT_SUCCESS(Status)) return cwc;
6498 return GDI_ERROR;
6499 }
6500
6501 /* EOF */