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