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