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