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