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