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