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