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