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