31bbf37fc7b5b68fc88a86c0b2f6f46cd67f0a19
[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 FillTMEx(TEXTMETRICW *TM, PFONTGDI FontGDI,
2238 TT_OS2 *pOS2, TT_HoriHeader *pHori,
2239 FT_WinFNT_HeaderRec *pFNT, BOOL RealFont)
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 if (RealFont)
2268 {
2269 TM->tmWeight = FontGDI->OriginalWeight;
2270 TM->tmItalic = FontGDI->OriginalItalic;
2271 TM->tmUnderlined = pFNT->underline;
2272 TM->tmStruckOut = pFNT->strike_out;
2273 TM->tmCharSet = pFNT->charset;
2274 }
2275 else
2276 {
2277 TM->tmWeight = FontGDI->RequestWeight;
2278 TM->tmItalic = FontGDI->RequestItalic;
2279 TM->tmUnderlined = FontGDI->RequestUnderline;
2280 TM->tmStruckOut = FontGDI->RequestStrikeOut;
2281 TM->tmCharSet = FontGDI->CharSet;
2282 }
2283 return;
2284 }
2285
2286 if ((FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent == 0)
2287 {
2288 Ascent = pHori->Ascender;
2289 Descent = -pHori->Descender;
2290 }
2291 else
2292 {
2293 Ascent = (FT_Short)pOS2->usWinAscent;
2294 Descent = (FT_Short)pOS2->usWinDescent;
2295 }
2296
2297 TM->tmAscent = FontGDI->tmAscent;
2298 TM->tmDescent = FontGDI->tmDescent;
2299 TM->tmHeight = TM->tmAscent + TM->tmDescent;
2300 TM->tmInternalLeading = FontGDI->tmInternalLeading;
2301
2302 /* MSDN says:
2303 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2304 */
2305 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
2306 - ((Ascent + Descent)
2307 - (pHori->Ascender - pHori->Descender)),
2308 YScale) + 32) >> 6);
2309
2310 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
2311 if (TM->tmAveCharWidth == 0)
2312 {
2313 TM->tmAveCharWidth = 1;
2314 }
2315
2316 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
2317 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
2318
2319 if (RealFont)
2320 {
2321 TM->tmWeight = FontGDI->OriginalWeight;
2322 }
2323 else
2324 {
2325 if (FontGDI->OriginalWeight != FW_DONTCARE &&
2326 FontGDI->OriginalWeight != FW_NORMAL)
2327 {
2328 TM->tmWeight = FontGDI->OriginalWeight;
2329 }
2330 else
2331 {
2332 TM->tmWeight = FontGDI->RequestWeight;
2333 }
2334 }
2335
2336 TM->tmOverhang = 0;
2337 TM->tmDigitizedAspectX = 96;
2338 TM->tmDigitizedAspectY = 96;
2339 if (face_has_symbol_charmap(Face) ||
2340 (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
2341 {
2342 USHORT cpOEM, cpAnsi;
2343
2344 EngGetCurrentCodePage(&cpOEM, &cpAnsi);
2345 TM->tmFirstChar = 0;
2346 switch(cpAnsi)
2347 {
2348 case 1257: /* Baltic */
2349 TM->tmLastChar = 0xf8fd;
2350 break;
2351 default:
2352 TM->tmLastChar = 0xf0ff;
2353 }
2354 TM->tmBreakChar = 0x20;
2355 TM->tmDefaultChar = 0x1f;
2356 }
2357 else
2358 {
2359 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
2360 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
2361
2362 if(pOS2->usFirstCharIndex <= 1)
2363 TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
2364 else if (pOS2->usFirstCharIndex > 0xff)
2365 TM->tmBreakChar = 0x20;
2366 else
2367 TM->tmBreakChar = pOS2->usFirstCharIndex;
2368 TM->tmDefaultChar = TM->tmBreakChar - 1;
2369 }
2370
2371 if (RealFont)
2372 {
2373 TM->tmItalic = FontGDI->OriginalItalic;
2374 TM->tmUnderlined = FALSE;
2375 TM->tmStruckOut = FALSE;
2376 }
2377 else
2378 {
2379 if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
2380 {
2381 TM->tmItalic = 0xFF;
2382 }
2383 else
2384 {
2385 TM->tmItalic = 0;
2386 }
2387 TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
2388 TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
2389 }
2390
2391 if (!FT_IS_FIXED_WIDTH(Face))
2392 {
2393 switch (pOS2->panose[PAN_PROPORTION_INDEX])
2394 {
2395 case PAN_PROP_MONOSPACED:
2396 TM->tmPitchAndFamily = 0;
2397 break;
2398 default:
2399 TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH;
2400 break;
2401 }
2402 }
2403 else
2404 {
2405 TM->tmPitchAndFamily = 0;
2406 }
2407
2408 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
2409 {
2410 case PAN_FAMILY_SCRIPT:
2411 TM->tmPitchAndFamily |= FF_SCRIPT;
2412 break;
2413 case PAN_FAMILY_DECORATIVE:
2414 TM->tmPitchAndFamily |= FF_DECORATIVE;
2415 break;
2416
2417 case PAN_ANY:
2418 case PAN_NO_FIT:
2419 case PAN_FAMILY_TEXT_DISPLAY:
2420 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
2421 /* Which is clearly not what the panose spec says. */
2422 if (TM->tmPitchAndFamily == 0) /* Fixed */
2423 {
2424 TM->tmPitchAndFamily = FF_MODERN;
2425 }
2426 else
2427 {
2428 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
2429 {
2430 case PAN_ANY:
2431 case PAN_NO_FIT:
2432 default:
2433 TM->tmPitchAndFamily |= FF_DONTCARE;
2434 break;
2435
2436 case PAN_SERIF_COVE:
2437 case PAN_SERIF_OBTUSE_COVE:
2438 case PAN_SERIF_SQUARE_COVE:
2439 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2440 case PAN_SERIF_SQUARE:
2441 case PAN_SERIF_THIN:
2442 case PAN_SERIF_BONE:
2443 case PAN_SERIF_EXAGGERATED:
2444 case PAN_SERIF_TRIANGLE:
2445 TM->tmPitchAndFamily |= FF_ROMAN;
2446 break;
2447
2448 case PAN_SERIF_NORMAL_SANS:
2449 case PAN_SERIF_OBTUSE_SANS:
2450 case PAN_SERIF_PERP_SANS:
2451 case PAN_SERIF_FLARED:
2452 case PAN_SERIF_ROUNDED:
2453 TM->tmPitchAndFamily |= FF_SWISS;
2454 break;
2455 }
2456 }
2457 break;
2458 default:
2459 TM->tmPitchAndFamily |= FF_DONTCARE;
2460 }
2461
2462 if (FT_IS_SCALABLE(Face))
2463 {
2464 TM->tmPitchAndFamily |= TMPF_VECTOR;
2465 }
2466 if (FT_IS_SFNT(Face))
2467 {
2468 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
2469 }
2470
2471 TM->tmCharSet = FontGDI->CharSet;
2472 }
2473
2474 static void FASTCALL
2475 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
2476 TT_OS2 *pOS2, TT_HoriHeader *pHori,
2477 FT_WinFNT_HeaderRec *pFNT)
2478 {
2479 FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
2480 }
2481
2482 static NTSTATUS
2483 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
2484 FT_UShort NameID, FT_UShort LangID);
2485
2486 typedef struct FONT_NAMES
2487 {
2488 UNICODE_STRING FamilyNameW; /* family name (TT_NAME_ID_FONT_FAMILY) */
2489 UNICODE_STRING FaceNameW; /* face name (TT_NAME_ID_FULL_NAME) */
2490 UNICODE_STRING StyleNameW; /* style name (TT_NAME_ID_FONT_SUBFAMILY) */
2491 UNICODE_STRING FullNameW; /* unique name (TT_NAME_ID_UNIQUE_ID) */
2492 ULONG OtmSize; /* size of OUTLINETEXTMETRICW with extra data */
2493 } FONT_NAMES, *LPFONT_NAMES;
2494
2495 static __inline void FASTCALL
2496 IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace)
2497 {
2498 ULONG OtmSize;
2499
2500 RtlInitUnicodeString(&Names->FamilyNameW, NULL);
2501 RtlInitUnicodeString(&Names->FaceNameW, NULL);
2502 RtlInitUnicodeString(&Names->StyleNameW, NULL);
2503 RtlInitUnicodeString(&Names->FullNameW, NULL);
2504
2505 /* family name */
2506 IntGetFontLocalizedName(&Names->FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
2507 /* face name */
2508 IntGetFontLocalizedName(&Names->FaceNameW, SharedFace, TT_NAME_ID_FULL_NAME, gusLanguageID);
2509 /* style name */
2510 IntGetFontLocalizedName(&Names->StyleNameW, SharedFace, TT_NAME_ID_FONT_SUBFAMILY, gusLanguageID);
2511 /* unique name (full name) */
2512 IntGetFontLocalizedName(&Names->FullNameW, SharedFace, TT_NAME_ID_UNIQUE_ID, gusLanguageID);
2513
2514 /* Calculate the size of OUTLINETEXTMETRICW with extra data */
2515 OtmSize = sizeof(OUTLINETEXTMETRICW) +
2516 Names->FamilyNameW.Length + sizeof(UNICODE_NULL) +
2517 Names->FaceNameW.Length + sizeof(UNICODE_NULL) +
2518 Names->StyleNameW.Length + sizeof(UNICODE_NULL) +
2519 Names->FullNameW.Length + sizeof(UNICODE_NULL);
2520 Names->OtmSize = OtmSize;
2521 }
2522
2523 static __inline SIZE_T FASTCALL
2524 IntStoreName(const UNICODE_STRING *pName, BYTE *pb)
2525 {
2526 RtlCopyMemory(pb, pName->Buffer, pName->Length);
2527 *(WCHAR *)&pb[pName->Length] = UNICODE_NULL;
2528 return pName->Length + sizeof(UNICODE_NULL);
2529 }
2530
2531 static __inline BYTE *FASTCALL
2532 IntStoreFontNames(const FONT_NAMES *Names, OUTLINETEXTMETRICW *Otm)
2533 {
2534 BYTE *pb = (BYTE *)Otm + sizeof(OUTLINETEXTMETRICW);
2535
2536 /* family name */
2537 Otm->otmpFamilyName = (LPSTR)(pb - (BYTE*) Otm);
2538 pb += IntStoreName(&Names->FamilyNameW, pb);
2539
2540 /* face name */
2541 Otm->otmpFaceName = (LPSTR)(pb - (BYTE*) Otm);
2542 pb += IntStoreName(&Names->FaceNameW, pb);
2543
2544 /* style name */
2545 Otm->otmpStyleName = (LPSTR)(pb - (BYTE*) Otm);
2546 pb += IntStoreName(&Names->StyleNameW, pb);
2547
2548 /* unique name (full name) */
2549 Otm->otmpFullName = (LPSTR)(pb - (BYTE*) Otm);
2550 pb += IntStoreName(&Names->FullNameW, pb);
2551
2552 return pb;
2553 }
2554
2555 static __inline void FASTCALL
2556 IntFreeFontNames(FONT_NAMES *Names)
2557 {
2558 RtlFreeUnicodeString(&Names->FamilyNameW);
2559 RtlFreeUnicodeString(&Names->FaceNameW);
2560 RtlFreeUnicodeString(&Names->StyleNameW);
2561 RtlFreeUnicodeString(&Names->FullNameW);
2562 }
2563
2564 /*************************************************************
2565 * IntGetOutlineTextMetrics
2566 *
2567 */
2568 INT FASTCALL
2569 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
2570 UINT Size,
2571 OUTLINETEXTMETRICW *Otm)
2572 {
2573 TT_OS2 *pOS2;
2574 TT_HoriHeader *pHori;
2575 TT_Postscript *pPost;
2576 FT_Fixed XScale, YScale;
2577 FT_WinFNT_HeaderRec WinFNT;
2578 FT_Error Error;
2579 BYTE *pb;
2580 FONT_NAMES FontNames;
2581 PSHARED_FACE SharedFace = FontGDI->SharedFace;
2582 PSHARED_FACE_CACHE Cache;
2583 FT_Face Face = SharedFace->Face;
2584
2585 if (PRIMARYLANGID(gusLanguageID) == LANG_ENGLISH)
2586 {
2587 Cache = &SharedFace->EnglishUS;
2588 }
2589 else
2590 {
2591 Cache = &SharedFace->UserLanguage;
2592 }
2593
2594 if (Size == 0 && Cache->OutlineRequiredSize > 0)
2595 {
2596 ASSERT(Otm == NULL);
2597 return Cache->OutlineRequiredSize;
2598 }
2599
2600 IntInitFontNames(&FontNames, SharedFace);
2601 Cache->OutlineRequiredSize = FontNames.OtmSize;
2602
2603 if (Size == 0)
2604 {
2605 ASSERT(Otm == NULL);
2606 IntFreeFontNames(&FontNames);
2607 return Cache->OutlineRequiredSize;
2608 }
2609
2610 ASSERT(Otm != NULL);
2611
2612 if (Size < Cache->OutlineRequiredSize)
2613 {
2614 DPRINT1("Size %u < OutlineRequiredSize %u\n", Size,
2615 Cache->OutlineRequiredSize);
2616 IntFreeFontNames(&FontNames);
2617 return 0; /* failure */
2618 }
2619
2620 XScale = Face->size->metrics.x_scale;
2621 YScale = Face->size->metrics.y_scale;
2622
2623 IntLockFreeType();
2624
2625 pOS2 = FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
2626 pHori = FT_Get_Sfnt_Table(Face, FT_SFNT_HHEA);
2627 pPost = FT_Get_Sfnt_Table(Face, FT_SFNT_POST); /* We can live with this failing */
2628 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
2629
2630 if (pOS2 == NULL && Error)
2631 {
2632 IntUnLockFreeType();
2633 DPRINT1("Can't find OS/2 table - not TT font?\n");
2634 IntFreeFontNames(&FontNames);
2635 return 0;
2636 }
2637
2638 if (pHori == NULL && Error)
2639 {
2640 IntUnLockFreeType();
2641 DPRINT1("Can't find HHEA table - not TT font?\n");
2642 IntFreeFontNames(&FontNames);
2643 return 0;
2644 }
2645
2646 Otm->otmSize = Cache->OutlineRequiredSize;
2647
2648 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &WinFNT : 0);
2649
2650 if (!pOS2)
2651 goto skip_os2;
2652
2653 Otm->otmFiller = 0;
2654 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
2655 Otm->otmfsSelection = pOS2->fsSelection;
2656 Otm->otmfsType = pOS2->fsType;
2657 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
2658 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
2659 Otm->otmItalicAngle = 0; /* POST table */
2660 Otm->otmEMSquare = Face->units_per_EM;
2661
2662 #define SCALE_X(value) ((FT_MulFix((value), XScale) + 32) >> 6)
2663 #define SCALE_Y(value) ((FT_MulFix((value), YScale) + 32) >> 6)
2664
2665 Otm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
2666 Otm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
2667 Otm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
2668 Otm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
2669 Otm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
2670 Otm->otmrcFontBox.left = SCALE_X(Face->bbox.xMin);
2671 Otm->otmrcFontBox.right = SCALE_X(Face->bbox.xMax);
2672 Otm->otmrcFontBox.top = SCALE_Y(Face->bbox.yMax);
2673 Otm->otmrcFontBox.bottom = SCALE_Y(Face->bbox.yMin);
2674 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
2675 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
2676 Otm->otmMacLineGap = Otm->otmLineGap;
2677 Otm->otmusMinimumPPEM = 0; /* TT Header */
2678 Otm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
2679 Otm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
2680 Otm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
2681 Otm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
2682 Otm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
2683 Otm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
2684 Otm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
2685 Otm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
2686 Otm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
2687 Otm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
2688
2689 if (!pPost)
2690 {
2691 Otm->otmsUnderscoreSize = 0;
2692 Otm->otmsUnderscorePosition = 0;
2693 }
2694 else
2695 {
2696 Otm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
2697 Otm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
2698 }
2699
2700 #undef SCALE_X
2701 #undef SCALE_Y
2702
2703 skip_os2:
2704 IntUnLockFreeType();
2705
2706 pb = IntStoreFontNames(&FontNames, Otm);
2707 ASSERT(pb - (BYTE*)Otm == Cache->OutlineRequiredSize);
2708
2709 IntFreeFontNames(&FontNames);
2710
2711 return Cache->OutlineRequiredSize;
2712 }
2713
2714 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
2715 static BYTE
2716 CharSetFromLangID(LANGID LangID)
2717 {
2718 /* FIXME: Add more and fix if wrong */
2719 switch (PRIMARYLANGID(LangID))
2720 {
2721 case LANG_CHINESE:
2722 switch (SUBLANGID(LangID))
2723 {
2724 case SUBLANG_CHINESE_TRADITIONAL:
2725 return CHINESEBIG5_CHARSET;
2726 case SUBLANG_CHINESE_SIMPLIFIED:
2727 default:
2728 break;
2729 }
2730 return GB2312_CHARSET;
2731
2732 case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
2733 case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
2734 return EASTEUROPE_CHARSET;
2735
2736 case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
2737 case LANG_SERBIAN: case LANG_UKRAINIAN:
2738 return RUSSIAN_CHARSET;
2739
2740 case LANG_ARABIC: return ARABIC_CHARSET;
2741 case LANG_GREEK: return GREEK_CHARSET;
2742 case LANG_HEBREW: return HEBREW_CHARSET;
2743 case LANG_JAPANESE: return SHIFTJIS_CHARSET;
2744 case LANG_KOREAN: return JOHAB_CHARSET;
2745 case LANG_TURKISH: return TURKISH_CHARSET;
2746 case LANG_THAI: return THAI_CHARSET;
2747 case LANG_LATVIAN: return BALTIC_CHARSET;
2748 case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
2749
2750 case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
2751 case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
2752 case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
2753 case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
2754 case LANG_SWEDISH: default:
2755 return ANSI_CHARSET;
2756 }
2757 }
2758
2759 static void
2760 SwapEndian(LPVOID pvData, DWORD Size)
2761 {
2762 BYTE b, *pb = pvData;
2763 Size /= 2;
2764 while (Size-- > 0)
2765 {
2766 b = pb[0];
2767 pb[0] = pb[1];
2768 pb[1] = b;
2769 ++pb; ++pb;
2770 }
2771 }
2772
2773 static NTSTATUS
2774 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
2775 FT_UShort NameID, FT_UShort LangID)
2776 {
2777 FT_SfntName Name;
2778 INT i, Count, BestIndex, Score, BestScore;
2779 FT_Error Error;
2780 NTSTATUS Status = STATUS_NOT_FOUND;
2781 ANSI_STRING AnsiName;
2782 PSHARED_FACE_CACHE Cache;
2783 FT_Face Face = SharedFace->Face;
2784
2785 RtlFreeUnicodeString(pNameW);
2786
2787 /* select cache */
2788 if (PRIMARYLANGID(LangID) == LANG_ENGLISH)
2789 {
2790 Cache = &SharedFace->EnglishUS;
2791 }
2792 else
2793 {
2794 Cache = &SharedFace->UserLanguage;
2795 }
2796
2797 /* use cache if available */
2798 if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer)
2799 {
2800 return DuplicateUnicodeString(&Cache->FontFamily, pNameW);
2801 }
2802 if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer)
2803 {
2804 return DuplicateUnicodeString(&Cache->FullName, pNameW);
2805 }
2806
2807 BestIndex = -1;
2808 BestScore = 0;
2809
2810 Count = FT_Get_Sfnt_Name_Count(Face);
2811 for (i = 0; i < Count; ++i)
2812 {
2813 Error = FT_Get_Sfnt_Name(Face, i, &Name);
2814 if (Error)
2815 {
2816 continue; /* failure */
2817 }
2818
2819 if (Name.name_id != NameID)
2820 {
2821 continue; /* mismatched */
2822 }
2823
2824 if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
2825 (Name.encoding_id != TT_MS_ID_UNICODE_CS &&
2826 Name.encoding_id != TT_MS_ID_SYMBOL_CS))
2827 {
2828 continue; /* not Microsoft Unicode name */
2829 }
2830
2831 if (Name.string == NULL || Name.string_len == 0 ||
2832 (Name.string[0] == 0 && Name.string[1] == 0))
2833 {
2834 continue; /* invalid string */
2835 }
2836
2837 if (Name.language_id == LangID)
2838 {
2839 Score = 30;
2840 BestIndex = i;
2841 break; /* best match */
2842 }
2843 else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID))
2844 {
2845 Score = 20;
2846 }
2847 else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH)
2848 {
2849 Score = 10;
2850 }
2851 else
2852 {
2853 Score = 0;
2854 }
2855
2856 if (Score > BestScore)
2857 {
2858 BestScore = Score;
2859 BestIndex = i;
2860 }
2861 }
2862
2863 if (BestIndex >= 0)
2864 {
2865 /* store the best name */
2866 Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
2867 if (!Error)
2868 {
2869 /* NOTE: Name.string is not null-terminated */
2870 UNICODE_STRING Tmp;
2871 Tmp.Buffer = (PWCH)Name.string;
2872 Tmp.Length = Tmp.MaximumLength = Name.string_len;
2873
2874 pNameW->Length = 0;
2875 pNameW->MaximumLength = Name.string_len + sizeof(WCHAR);
2876 pNameW->Buffer = ExAllocatePoolWithTag(PagedPool, pNameW->MaximumLength, TAG_USTR);
2877
2878 if (pNameW->Buffer)
2879 {
2880 Status = RtlAppendUnicodeStringToString(pNameW, &Tmp);
2881 if (Status == STATUS_SUCCESS)
2882 {
2883 /* Convert UTF-16 big endian to little endian */
2884 SwapEndian(pNameW->Buffer, pNameW->Length);
2885 }
2886 }
2887 else
2888 {
2889 Status = STATUS_INSUFFICIENT_RESOURCES;
2890 }
2891 }
2892 }
2893
2894 if (!NT_SUCCESS(Status))
2895 {
2896 /* defaulted */
2897 if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
2898 {
2899 RtlInitAnsiString(&AnsiName, Face->style_name);
2900 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2901 }
2902 else
2903 {
2904 RtlInitAnsiString(&AnsiName, Face->family_name);
2905 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
2906 }
2907 }
2908
2909 if (NT_SUCCESS(Status))
2910 {
2911 /* make cache */
2912 if (NameID == TT_NAME_ID_FONT_FAMILY)
2913 {
2914 ASSERT_FREETYPE_LOCK_NOT_HELD();
2915 IntLockFreeType();
2916 if (!Cache->FontFamily.Buffer)
2917 DuplicateUnicodeString(pNameW, &Cache->FontFamily);
2918 IntUnLockFreeType();
2919 }
2920 else if (NameID == TT_NAME_ID_FULL_NAME)
2921 {
2922 ASSERT_FREETYPE_LOCK_NOT_HELD();
2923 IntLockFreeType();
2924 if (!Cache->FullName.Buffer)
2925 DuplicateUnicodeString(pNameW, &Cache->FullName);
2926 IntUnLockFreeType();
2927 }
2928 }
2929
2930 return Status;
2931 }
2932
2933 static void FASTCALL
2934 FontFamilyFillInfo(PFONTFAMILYINFO Info, LPCWSTR FaceName,
2935 LPCWSTR FullName, PFONTGDI FontGDI)
2936 {
2937 ANSI_STRING StyleA;
2938 UNICODE_STRING StyleW;
2939 TT_OS2 *pOS2;
2940 FONTSIGNATURE fs;
2941 CHARSETINFO CharSetInfo;
2942 unsigned i, Size;
2943 OUTLINETEXTMETRICW *Otm;
2944 LOGFONTW *Lf;
2945 TEXTMETRICW *TM;
2946 NEWTEXTMETRICW *Ntm;
2947 DWORD fs0;
2948 NTSTATUS status;
2949 PSHARED_FACE SharedFace = FontGDI->SharedFace;
2950 FT_Face Face = SharedFace->Face;
2951 UNICODE_STRING NameW;
2952
2953 RtlInitUnicodeString(&NameW, NULL);
2954 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
2955 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2956 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2957 if (!Otm)
2958 {
2959 return;
2960 }
2961 Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2962 if (!Size)
2963 {
2964 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2965 return;
2966 }
2967
2968 Lf = &Info->EnumLogFontEx.elfLogFont;
2969 TM = &Otm->otmTextMetrics;
2970
2971 Lf->lfHeight = TM->tmHeight;
2972 Lf->lfWidth = TM->tmAveCharWidth;
2973 Lf->lfWeight = TM->tmWeight;
2974 Lf->lfItalic = TM->tmItalic;
2975 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
2976 Lf->lfCharSet = TM->tmCharSet;
2977 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
2978 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
2979 Lf->lfQuality = PROOF_QUALITY;
2980
2981 Ntm = &Info->NewTextMetricEx.ntmTm;
2982 Ntm->tmHeight = TM->tmHeight;
2983 Ntm->tmAscent = TM->tmAscent;
2984 Ntm->tmDescent = TM->tmDescent;
2985 Ntm->tmInternalLeading = TM->tmInternalLeading;
2986 Ntm->tmExternalLeading = TM->tmExternalLeading;
2987 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
2988 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
2989 Ntm->tmWeight = TM->tmWeight;
2990 Ntm->tmOverhang = TM->tmOverhang;
2991 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
2992 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
2993 Ntm->tmFirstChar = TM->tmFirstChar;
2994 Ntm->tmLastChar = TM->tmLastChar;
2995 Ntm->tmDefaultChar = TM->tmDefaultChar;
2996 Ntm->tmBreakChar = TM->tmBreakChar;
2997 Ntm->tmItalic = TM->tmItalic;
2998 Ntm->tmUnderlined = TM->tmUnderlined;
2999 Ntm->tmStruckOut = TM->tmStruckOut;
3000 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
3001 Ntm->tmCharSet = TM->tmCharSet;
3002 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
3003
3004 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
3005
3006 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
3007
3008 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
3009 ? TRUETYPE_FONTTYPE : 0);
3010
3011 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
3012 Info->FontType |= RASTER_FONTTYPE;
3013
3014
3015 /* face name */
3016 if (!FaceName)
3017 FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
3018
3019 RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
3020
3021 /* full name */
3022 if (!FullName)
3023 FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName);
3024
3025 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
3026 sizeof(Info->EnumLogFontEx.elfFullName),
3027 FullName);
3028
3029 RtlInitAnsiString(&StyleA, Face->style_name);
3030 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
3031 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
3032 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
3033 if (!NT_SUCCESS(status))
3034 {
3035 ExFreePoolWithTag(Otm, GDITAG_TEXT);
3036 return;
3037 }
3038 Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
3039
3040 IntLockFreeType();
3041 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3042
3043 if (!pOS2)
3044 {
3045 IntUnLockFreeType();
3046 ExFreePoolWithTag(Otm, GDITAG_TEXT);
3047 return;
3048 }
3049
3050 Ntm->ntmSizeEM = Otm->otmEMSquare;
3051 Ntm->ntmCellHeight = (FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent;
3052 Ntm->ntmAvgWidth = 0;
3053
3054 ExFreePoolWithTag(Otm, GDITAG_TEXT);
3055
3056 fs.fsCsb[0] = pOS2->ulCodePageRange1;
3057 fs.fsCsb[1] = pOS2->ulCodePageRange2;
3058 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3059 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3060 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3061 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3062
3063 if (0 == pOS2->version)
3064 {
3065 FT_UInt Dummy;
3066
3067 if (FT_Get_First_Char(Face, &Dummy) < 0x100)
3068 fs.fsCsb[0] |= FS_LATIN1;
3069 else
3070 fs.fsCsb[0] |= FS_SYMBOL;
3071 }
3072 IntUnLockFreeType();
3073
3074 if (fs.fsCsb[0] == 0)
3075 {
3076 /* Let's see if we can find any interesting cmaps */
3077 for (i = 0; i < (UINT)Face->num_charmaps; i++)
3078 {
3079 switch (Face->charmaps[i]->encoding)
3080 {
3081 case FT_ENCODING_UNICODE:
3082 case FT_ENCODING_APPLE_ROMAN:
3083 fs.fsCsb[0] |= FS_LATIN1;
3084 break;
3085 case FT_ENCODING_MS_SYMBOL:
3086 fs.fsCsb[0] |= FS_SYMBOL;
3087 break;
3088 default:
3089 break;
3090 }
3091 }
3092 }
3093
3094 for (i = 0; i < MAXTCIINDEX; i++)
3095 {
3096 fs0 = 1L << i;
3097 if (fs.fsCsb[0] & fs0)
3098 {
3099 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
3100 {
3101 CharSetInfo.ciCharset = DEFAULT_CHARSET;
3102 }
3103 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
3104 {
3105 if (g_ElfScripts[i])
3106 wcscpy(Info->EnumLogFontEx.elfScript, g_ElfScripts[i]);
3107 else
3108 {
3109 DPRINT1("Unknown elfscript for bit %u\n", i);
3110 }
3111 }
3112 }
3113 }
3114 Info->NewTextMetricEx.ntmFontSig = fs;
3115 }
3116
3117 static BOOLEAN FASTCALL
3118 GetFontFamilyInfoForList(const LOGFONTW *LogFont,
3119 PFONTFAMILYINFO Info,
3120 LPCWSTR NominalName,
3121 LONG *pCount,
3122 LONG MaxCount,
3123 PLIST_ENTRY Head)
3124 {
3125 PLIST_ENTRY Entry;
3126 PFONT_ENTRY CurrentEntry;
3127 FONTGDI *FontGDI;
3128 FONTFAMILYINFO InfoEntry;
3129 LONG Count = *pCount;
3130
3131 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
3132 {
3133 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
3134 FontGDI = CurrentEntry->Font;
3135 ASSERT(FontGDI);
3136
3137 if (LogFont->lfCharSet != DEFAULT_CHARSET &&
3138 LogFont->lfCharSet != FontGDI->CharSet)
3139 {
3140 continue; /* charset mismatch */
3141 }
3142
3143 /* get one info entry */
3144 FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
3145
3146 if (LogFont->lfFaceName[0] != UNICODE_NULL)
3147 {
3148 /* check name */
3149 if (_wcsnicmp(LogFont->lfFaceName,
3150 InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
3151 RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0 &&
3152 _wcsnicmp(LogFont->lfFaceName,
3153 InfoEntry.EnumLogFontEx.elfFullName,
3154 RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0)
3155 {
3156 continue;
3157 }
3158 }
3159
3160 if (NominalName)
3161 {
3162 /* store the nominal name */
3163 RtlStringCbCopyW(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
3164 sizeof(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName),
3165 NominalName);
3166 }
3167
3168 /* store one entry to Info */
3169 if (0 <= Count && Count < MaxCount)
3170 {
3171 RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
3172 }
3173 Count++;
3174 }
3175
3176 *pCount = Count;
3177
3178 return TRUE;
3179 }
3180
3181 static BOOLEAN FASTCALL
3182 GetFontFamilyInfoForSubstitutes(const LOGFONTW *LogFont,
3183 PFONTFAMILYINFO Info,
3184 LONG *pCount,
3185 LONG MaxCount)
3186 {
3187 PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead;
3188 PFONTSUBST_ENTRY pCurrentEntry;
3189 PUNICODE_STRING pFromW, pToW;
3190 LOGFONTW lf = *LogFont;
3191 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
3192
3193 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
3194 {
3195 pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
3196
3197 pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
3198 if (LogFont->lfFaceName[0] != UNICODE_NULL)
3199 {
3200 /* check name */
3201 if (_wcsicmp(LogFont->lfFaceName, pFromW->Buffer) != 0)
3202 continue; /* mismatch */
3203 }
3204
3205 pToW = &pCurrentEntry->FontNames[FONTSUBST_TO];
3206 if (RtlEqualUnicodeString(pFromW, pToW, TRUE) &&
3207 pCurrentEntry->CharSets[FONTSUBST_FROM] ==
3208 pCurrentEntry->CharSets[FONTSUBST_TO])
3209 {
3210 /* identical mapping */
3211 continue;
3212 }
3213
3214 /* substitute and get the real name */
3215 IntUnicodeStringToBuffer(lf.lfFaceName, sizeof(lf.lfFaceName), pFromW);
3216 SubstituteFontRecurse(&lf);
3217 if (LogFont->lfCharSet != DEFAULT_CHARSET && LogFont->lfCharSet != lf.lfCharSet)
3218 continue;
3219
3220 /* search in global fonts */
3221 IntLockGlobalFonts();
3222 GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount, &g_FontListHead);
3223 IntUnLockGlobalFonts();
3224
3225 /* search in private fonts */
3226 IntLockProcessPrivateFonts(Win32Process);
3227 GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount,
3228 &Win32Process->PrivateFontListHead);
3229 IntUnLockProcessPrivateFonts(Win32Process);
3230
3231 if (LogFont->lfFaceName[0] != UNICODE_NULL)
3232 {
3233 /* it's already matched to the exact name and charset if the name
3234 was specified at here, then so don't scan more for another name */
3235 break;
3236 }
3237 }
3238
3239 return TRUE;
3240 }
3241
3242 BOOL
3243 FASTCALL
3244 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
3245 {
3246 if ( lprs )
3247 {
3248 lprs->nSize = sizeof(RASTERIZER_STATUS);
3249 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
3250 lprs->nLanguageID = gusLanguageID;
3251 return TRUE;
3252 }
3253 EngSetLastError(ERROR_INVALID_PARAMETER);
3254 return FALSE;
3255 }
3256
3257 static
3258 BOOL
3259 SameScaleMatrix(
3260 PMATRIX pmx1,
3261 PMATRIX pmx2)
3262 {
3263 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
3264 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
3265 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
3266 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
3267 }
3268
3269 FT_BitmapGlyph APIENTRY
3270 ftGdiGlyphCacheGet(
3271 FT_Face Face,
3272 INT GlyphIndex,
3273 INT Height,
3274 FT_Render_Mode RenderMode,
3275 PMATRIX pmx)
3276 {
3277 PLIST_ENTRY CurrentEntry;
3278 PFONT_CACHE_ENTRY FontEntry;
3279
3280 ASSERT_FREETYPE_LOCK_HELD();
3281
3282 for (CurrentEntry = g_FontCacheListHead.Flink;
3283 CurrentEntry != &g_FontCacheListHead;
3284 CurrentEntry = CurrentEntry->Flink)
3285 {
3286 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
3287 if ((FontEntry->Face == Face) &&
3288 (FontEntry->GlyphIndex == GlyphIndex) &&
3289 (FontEntry->Height == Height) &&
3290 (FontEntry->RenderMode == RenderMode) &&
3291 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
3292 break;
3293 }
3294
3295 if (CurrentEntry == &g_FontCacheListHead)
3296 {
3297 return NULL;
3298 }
3299
3300 RemoveEntryList(CurrentEntry);
3301 InsertHeadList(&g_FontCacheListHead, CurrentEntry);
3302 return FontEntry->BitmapGlyph;
3303 }
3304
3305 /* no cache */
3306 FT_BitmapGlyph APIENTRY
3307 ftGdiGlyphSet(
3308 FT_Face Face,
3309 FT_GlyphSlot GlyphSlot,
3310 FT_Render_Mode RenderMode)
3311 {
3312 FT_Glyph Glyph;
3313 INT error;
3314 FT_Bitmap AlignedBitmap;
3315 FT_BitmapGlyph BitmapGlyph;
3316
3317 error = FT_Get_Glyph(GlyphSlot, &Glyph);
3318 if (error)
3319 {
3320 DPRINT1("Failure getting glyph.\n");
3321 return NULL;
3322 }
3323
3324 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
3325 if (error)
3326 {
3327 FT_Done_Glyph(Glyph);
3328 DPRINT1("Failure rendering glyph.\n");
3329 return NULL;
3330 }
3331
3332 BitmapGlyph = (FT_BitmapGlyph)Glyph;
3333 FT_Bitmap_New(&AlignedBitmap);
3334 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
3335 {
3336 DPRINT1("Conversion failed\n");
3337 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
3338 return NULL;
3339 }
3340
3341 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
3342 BitmapGlyph->bitmap = AlignedBitmap;
3343
3344 return BitmapGlyph;
3345 }
3346
3347 FT_BitmapGlyph APIENTRY
3348 ftGdiGlyphCacheSet(
3349 FT_Face Face,
3350 INT GlyphIndex,
3351 INT Height,
3352 PMATRIX pmx,
3353 FT_GlyphSlot GlyphSlot,
3354 FT_Render_Mode RenderMode)
3355 {
3356 FT_Glyph GlyphCopy;
3357 INT error;
3358 PFONT_CACHE_ENTRY NewEntry;
3359 FT_Bitmap AlignedBitmap;
3360 FT_BitmapGlyph BitmapGlyph;
3361
3362 ASSERT_FREETYPE_LOCK_HELD();
3363
3364 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
3365 if (error)
3366 {
3367 DPRINT1("Failure caching glyph.\n");
3368 return NULL;
3369 };
3370
3371 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
3372 if (error)
3373 {
3374 FT_Done_Glyph(GlyphCopy);
3375 DPRINT1("Failure rendering glyph.\n");
3376 return NULL;
3377 };
3378
3379 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
3380 if (!NewEntry)
3381 {
3382 DPRINT1("Alloc failure caching glyph.\n");
3383 FT_Done_Glyph(GlyphCopy);
3384 return NULL;
3385 }
3386
3387 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
3388 FT_Bitmap_New(&AlignedBitmap);
3389 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
3390 {
3391 DPRINT1("Conversion failed\n");
3392 ExFreePoolWithTag(NewEntry, TAG_FONT);
3393 FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
3394 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
3395 return NULL;
3396 }
3397
3398 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
3399 BitmapGlyph->bitmap = AlignedBitmap;
3400
3401 NewEntry->GlyphIndex = GlyphIndex;
3402 NewEntry->Face = Face;
3403 NewEntry->BitmapGlyph = BitmapGlyph;
3404 NewEntry->Height = Height;
3405 NewEntry->RenderMode = RenderMode;
3406 NewEntry->mxWorldToDevice = *pmx;
3407
3408 InsertHeadList(&g_FontCacheListHead, &NewEntry->ListEntry);
3409 if (++g_FontCacheNumEntries > MAX_FONT_CACHE)
3410 {
3411 NewEntry = CONTAINING_RECORD(g_FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
3412 RemoveCachedEntry(NewEntry);
3413 }
3414
3415 return BitmapGlyph;
3416 }
3417
3418
3419 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3420 {
3421 TTPOLYGONHEADER *pph;
3422 TTPOLYCURVE *ppc;
3423 int needed = 0, point = 0, contour, first_pt;
3424 unsigned int pph_start, cpfx;
3425 DWORD type;
3426
3427 for (contour = 0; contour < outline->n_contours; contour++)
3428 {
3429 /* Ignore contours containing one point */
3430 if (point == outline->contours[contour])
3431 {
3432 point++;
3433 continue;
3434 }
3435
3436 pph_start = needed;
3437 pph = (TTPOLYGONHEADER *)(buf + needed);
3438 first_pt = point;
3439 if (buf)
3440 {
3441 pph->dwType = TT_POLYGON_TYPE;
3442 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3443 }
3444 needed += sizeof(*pph);
3445 point++;
3446 while (point <= outline->contours[contour])
3447 {
3448 ppc = (TTPOLYCURVE *)(buf + needed);
3449 type = outline->tags[point] & FT_Curve_Tag_On ?
3450 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3451 cpfx = 0;
3452 do
3453 {
3454 if (buf)
3455 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3456 cpfx++;
3457 point++;
3458 } while (point <= outline->contours[contour] &&
3459 (outline->tags[point] & FT_Curve_Tag_On) ==
3460 (outline->tags[point-1] & FT_Curve_Tag_On));
3461 /* At the end of a contour Windows adds the start point, but
3462 only for Beziers */
3463 if (point > outline->contours[contour] &&
3464 !(outline->tags[point-1] & FT_Curve_Tag_On))
3465 {
3466 if (buf)
3467 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3468 cpfx++;
3469 }
3470 else if (point <= outline->contours[contour] &&
3471 outline->tags[point] & FT_Curve_Tag_On)
3472 {
3473 /* add closing pt for bezier */
3474 if (buf)
3475 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3476 cpfx++;
3477 point++;
3478 }
3479 if (buf)
3480 {
3481 ppc->wType = type;
3482 ppc->cpfx = cpfx;
3483 }
3484 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3485 }
3486 if (buf)
3487 pph->cb = needed - pph_start;
3488 }
3489 return needed;
3490 }
3491
3492 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3493 {
3494 /* Convert the quadratic Beziers to cubic Beziers.
3495 The parametric eqn for a cubic Bezier is, from PLRM:
3496 r(t) = at^3 + bt^2 + ct + r0
3497 with the control points:
3498 r1 = r0 + c/3
3499 r2 = r1 + (c + b)/3
3500 r3 = r0 + c + b + a
3501
3502 A quadratic Bezier has the form:
3503 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3504
3505 So equating powers of t leads to:
3506 r1 = 2/3 p1 + 1/3 p0
3507 r2 = 2/3 p1 + 1/3 p2
3508 and of course r0 = p0, r3 = p2
3509 */
3510 int contour, point = 0, first_pt;
3511 TTPOLYGONHEADER *pph;
3512 TTPOLYCURVE *ppc;
3513 DWORD pph_start, cpfx, type;
3514 FT_Vector cubic_control[4];
3515 unsigned int needed = 0;
3516
3517 for (contour = 0; contour < outline->n_contours; contour++)
3518 {
3519 pph_start = needed;
3520 pph = (TTPOLYGONHEADER *)(buf + needed);
3521 first_pt = point;
3522 if (buf)
3523 {
3524 pph->dwType = TT_POLYGON_TYPE;
3525 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3526 }
3527 needed += sizeof(*pph);
3528 point++;
3529 while (point <= outline->contours[contour])
3530 {
3531 ppc = (TTPOLYCURVE *)(buf + needed);
3532 type = outline->tags[point] & FT_Curve_Tag_On ?
3533 TT_PRIM_LINE : TT_PRIM_CSPLINE;
3534 cpfx = 0;
3535 do
3536 {
3537 if (type == TT_PRIM_LINE)
3538 {
3539 if (buf)
3540 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3541 cpfx++;
3542 point++;
3543 }
3544 else
3545 {
3546 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
3547 so cpfx = 3n */
3548
3549 /* FIXME: Possible optimization in endpoint calculation
3550 if there are two consecutive curves */
3551 cubic_control[0] = outline->points[point-1];
3552 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
3553 {
3554 cubic_control[0].x += outline->points[point].x + 1;
3555 cubic_control[0].y += outline->points[point].y + 1;
3556 cubic_control[0].x >>= 1;
3557 cubic_control[0].y >>= 1;
3558 }
3559 if (point+1 > outline->contours[contour])
3560 cubic_control[3] = outline->points[first_pt];
3561 else
3562 {
3563 cubic_control[3] = outline->points[point+1];
3564 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
3565 {
3566 cubic_control[3].x += outline->points[point].x + 1;
3567 cubic_control[3].y += outline->points[point].y + 1;
3568 cubic_control[3].x >>= 1;
3569 cubic_control[3].y >>= 1;
3570 }
3571 }
3572 /* r1 = 1/3 p0 + 2/3 p1
3573 r2 = 1/3 p2 + 2/3 p1 */
3574 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3575 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3576 cubic_control[2] = cubic_control[1];
3577 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3578 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3579 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3580 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3581 if (buf)
3582 {
3583 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3584 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3585 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3586 }
3587 cpfx += 3;
3588 point++;
3589 }
3590 } while (point <= outline->contours[contour] &&
3591 (outline->tags[point] & FT_Curve_Tag_On) ==
3592 (outline->tags[point-1] & FT_Curve_Tag_On));
3593 /* At the end of a contour Windows adds the start point,
3594 but only for Beziers and we've already done that.
3595 */
3596 if (point <= outline->contours[contour] &&
3597 outline->tags[point] & FT_Curve_Tag_On)
3598 {
3599 /* This is the closing pt of a bezier, but we've already
3600 added it, so just inc point and carry on */
3601 point++;
3602 }
3603 if (buf)
3604 {
3605 ppc->wType = type;
3606 ppc->cpfx = cpfx;
3607 }
3608 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3609 }
3610 if (buf)
3611 pph->cb = needed - pph_start;
3612 }
3613 return needed;
3614 }
3615
3616 static FT_Error
3617 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
3618 {
3619 FT_Error error;
3620 FT_Size_RequestRec req;
3621 FT_Face face = FontGDI->SharedFace->Face;
3622 TT_OS2 *pOS2;
3623 TT_HoriHeader *pHori;
3624 FT_WinFNT_HeaderRec WinFNT;
3625 LONG Ascent, Descent, Sum, EmHeight64;
3626
3627 lfWidth = abs(lfWidth);
3628 if (lfHeight == 0)
3629 {
3630 if (lfWidth == 0)
3631 {
3632 DPRINT("lfHeight and lfWidth are zero.\n");
3633 lfHeight = -16;
3634 }
3635 else
3636 {
3637 lfHeight = lfWidth;
3638 }
3639 }
3640
3641 if (lfHeight == -1)
3642 lfHeight = -2;
3643
3644 ASSERT_FREETYPE_LOCK_HELD();
3645 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
3646 pHori = (TT_HoriHeader *)FT_Get_Sfnt_Table(face, FT_SFNT_HHEA);
3647
3648 if (!pOS2 || !pHori)
3649 {
3650 error = FT_Get_WinFNT_Header(face, &WinFNT);
3651 if (error)
3652 {
3653 DPRINT1("%s: Failed to request font size.\n", face->family_name);
3654 ASSERT(FALSE);
3655 return error;
3656 }
3657
3658 FontGDI->tmHeight = WinFNT.pixel_height;
3659 FontGDI->tmAscent = WinFNT.ascent;
3660 FontGDI->tmDescent = FontGDI->tmHeight - FontGDI->tmAscent;
3661 FontGDI->tmInternalLeading = WinFNT.internal_leading;
3662 FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3663 FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3664 FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3665 FontGDI->Magic = FONTGDI_MAGIC;
3666 return 0;
3667 }
3668
3669 /*
3670 * NOTE: We cast TT_OS2.usWinAscent and TT_OS2.usWinDescent to signed FT_Short.
3671 * Why? See: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswindescent
3672 *
3673 * > usWinDescent is "usually" a positive value ...
3674 *
3675 * We can read it as "not always". See CORE-14994.
3676 * See also: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fsselection
3677 */
3678 #define FM_SEL_USE_TYPO_METRICS 0x80
3679 if (lfHeight > 0)
3680 {
3681 /* case (A): lfHeight is positive */
3682 Sum = (FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent;
3683 if (Sum == 0 || (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS))
3684 {
3685 Ascent = pHori->Ascender;
3686 Descent = -pHori->Descender;
3687 Sum = Ascent + Descent;
3688 }
3689 else
3690 {
3691 Ascent = (FT_Short)pOS2->usWinAscent;
3692 Descent = (FT_Short)pOS2->usWinDescent;
3693 }
3694
3695 FontGDI->tmAscent = FT_MulDiv(lfHeight, Ascent, Sum);
3696 FontGDI->tmDescent = FT_MulDiv(lfHeight, Descent, Sum);
3697 FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3698 FontGDI->tmInternalLeading = FontGDI->tmHeight - FT_MulDiv(lfHeight, face->units_per_EM, Sum);
3699 }
3700 else if (lfHeight < 0)
3701 {
3702 /* case (B): lfHeight is negative */
3703 if (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS)
3704 {
3705 FontGDI->tmAscent = FT_MulDiv(-lfHeight, pHori->Ascender, face->units_per_EM);
3706 FontGDI->tmDescent = FT_MulDiv(-lfHeight, -pHori->Descender, face->units_per_EM);
3707 }
3708 else
3709 {
3710 FontGDI->tmAscent = FT_MulDiv(-lfHeight, (FT_Short)pOS2->usWinAscent, face->units_per_EM);
3711 FontGDI->tmDescent = FT_MulDiv(-lfHeight, (FT_Short)pOS2->usWinDescent, face->units_per_EM);
3712 }
3713 FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
3714 FontGDI->tmInternalLeading = FontGDI->tmHeight + lfHeight;
3715 }
3716 #undef FM_SEL_USE_TYPO_METRICS
3717
3718 FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
3719 FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
3720 FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
3721 FontGDI->Magic = FONTGDI_MAGIC;
3722
3723 EmHeight64 = (FontGDI->EmHeight << 6);
3724
3725 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
3726 req.width = 0;
3727 req.height = EmHeight64;
3728 req.horiResolution = 0;
3729 req.vertResolution = 0;
3730 return FT_Request_Size(face, &req);
3731 }
3732
3733 BOOL
3734 FASTCALL
3735 TextIntUpdateSize(PDC dc,
3736 PTEXTOBJ TextObj,
3737 PFONTGDI FontGDI,
3738 BOOL bDoLock)
3739 {
3740 FT_Face face;
3741 INT error, n;
3742 FT_CharMap charmap, found;
3743 LOGFONTW *plf;
3744
3745 if (bDoLock)
3746 IntLockFreeType();
3747
3748 face = FontGDI->SharedFace->Face;
3749 if (face->charmap == NULL)
3750 {
3751 DPRINT("WARNING: No charmap selected!\n");
3752 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3753
3754 found = NULL;
3755 for (n = 0; n < face->num_charmaps; n++)
3756 {
3757 charmap = face->charmaps[n];
3758 if (charmap->encoding == FT_ENCODING_UNICODE)
3759 {
3760 found = charmap;
3761 break;
3762 }
3763 }
3764 if (!found)
3765 {
3766 for (n = 0; n < face->num_charmaps; n++)
3767 {
3768 charmap = face->charmaps[n];
3769 if (charmap->platform_id == TT_PLATFORM_APPLE_UNICODE)
3770 {
3771 found = charmap;
3772 break;
3773 }
3774 }
3775 }
3776 if (!found)
3777 {
3778 for (n = 0; n < face->num_charmaps; n++)
3779 {
3780 charmap = face->charmaps[n];
3781 if (charmap->encoding == FT_ENCODING_MS_SYMBOL)
3782 {
3783 found = charmap;
3784 break;
3785 }
3786 }
3787 }
3788 if (!found && face->num_charmaps > 0)
3789 {
3790 found = face->charmaps[0];
3791 }
3792 if (!found)
3793 {
3794 DPRINT1("WARNING: Could not find desired charmap!\n");
3795 }
3796 else
3797 {
3798 DPRINT("Found charmap encoding: %i\n", found->encoding);
3799 error = FT_Set_Charmap(face, found);
3800 if (error)
3801 {
3802 DPRINT1("WARNING: Could not set the charmap!\n");
3803 }
3804 }
3805 }
3806
3807 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3808
3809 error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
3810
3811 if (bDoLock)
3812 IntUnLockFreeType();
3813
3814 if (error)
3815 {
3816 DPRINT1("Error in setting pixel sizes: %d\n", error);
3817 return FALSE;
3818 }
3819
3820 return TRUE;
3821 }
3822
3823 static inline FT_UInt FASTCALL
3824 get_glyph_index_symbol(FT_Face ft_face, UINT glyph)
3825 {
3826 FT_UInt ret;
3827
3828 if (glyph < 0x100) glyph += 0xf000;
3829 /* there are a number of old pre-Unicode "broken" TTFs, which
3830 do have symbols at U+00XX instead of U+f0XX */
3831 if (!(ret = FT_Get_Char_Index(ft_face, glyph)))
3832 ret = FT_Get_Char_Index(ft_face, glyph - 0xf000);
3833
3834 return ret;
3835 }
3836
3837 static inline FT_UInt FASTCALL
3838 get_glyph_index(FT_Face ft_face, UINT glyph)
3839 {
3840 FT_UInt ret;
3841
3842 if (face_has_symbol_charmap(ft_face))
3843 {
3844 ret = get_glyph_index_symbol(ft_face, glyph);
3845 if (ret != 0)
3846 return ret;
3847 }
3848
3849 return FT_Get_Char_Index(ft_face, glyph);
3850 }
3851
3852 static inline FT_UInt FASTCALL
3853 get_glyph_index_flagged(FT_Face face, FT_ULong code, DWORD indexed_flag, DWORD flags)
3854 {
3855 FT_UInt glyph_index;
3856 if (flags & indexed_flag)
3857 {
3858 glyph_index = code;
3859 }
3860 else
3861 {
3862 glyph_index = get_glyph_index(face, code);
3863 }
3864 return glyph_index;
3865 }
3866
3867 /*
3868 * Based on WineEngGetGlyphOutline
3869 *
3870 */
3871 ULONG
3872 FASTCALL
3873 ftGdiGetGlyphOutline(
3874 PDC dc,
3875 WCHAR wch,
3876 UINT iFormat,
3877 LPGLYPHMETRICS pgm,
3878 ULONG cjBuf,
3879 PVOID pvBuf,
3880 LPMAT2 pmat2,
3881 BOOL bIgnoreRotation)
3882 {
3883 PDC_ATTR pdcattr;
3884 PTEXTOBJ TextObj;
3885 PFONTGDI FontGDI;
3886 HFONT hFont = 0;
3887 GLYPHMETRICS gm;
3888 ULONG Size;
3889 FT_Face ft_face;
3890 FT_UInt glyph_index;
3891 DWORD width, height, pitch, needed = 0;
3892 FT_Bitmap ft_bitmap;
3893 FT_Error error;
3894 INT left, right, top = 0, bottom = 0;
3895 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3896 FLOATOBJ eM11, widthRatio, eTemp;
3897 FT_Matrix transMat = identityMat;
3898 BOOL needsTransform = FALSE;
3899 INT orientation;
3900 LONG aveWidth;
3901 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3902 OUTLINETEXTMETRICW *potm;
3903 XFORMOBJ xo;
3904 XFORML xform;
3905 LOGFONTW *plf;
3906
3907 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3908 cjBuf, pvBuf, pmat2);
3909
3910 pdcattr = dc->pdcattr;
3911
3912 XFORMOBJ_vInit(&xo, &dc->pdcattr->mxWorldToDevice);
3913 XFORMOBJ_iGetXform(&xo, &xform);
3914 FLOATOBJ_SetFloat(&eM11, xform.eM11);
3915
3916 hFont = pdcattr->hlfntNew;
3917 TextObj = RealizeFontInit(hFont);
3918
3919 if (!TextObj)
3920 {
3921 EngSetLastError(ERROR_INVALID_HANDLE);
3922 return GDI_ERROR;
3923 }
3924 FontGDI = ObjToGDI(TextObj->Font, FONT);
3925 ft_face = FontGDI->SharedFace->Face;
3926
3927 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3928 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3929 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3930
3931 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3932 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3933 if (!potm)
3934 {
3935 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3936 TEXTOBJ_UnlockText(TextObj);
3937 return GDI_ERROR;
3938 }
3939 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
3940 if (!Size)
3941 {
3942 /* FIXME: last error? */
3943 ExFreePoolWithTag(potm, GDITAG_TEXT);
3944 TEXTOBJ_UnlockText(TextObj);
3945 return GDI_ERROR;
3946 }
3947
3948 IntLockFreeType();
3949 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3950 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
3951
3952 TEXTOBJ_UnlockText(TextObj);
3953
3954 glyph_index = get_glyph_index_flagged(ft_face, wch, GGO_GLYPH_INDEX, iFormat);
3955 iFormat &= ~GGO_GLYPH_INDEX;
3956
3957 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3958 load_flags |= FT_LOAD_NO_BITMAP;
3959
3960 if (iFormat & GGO_UNHINTED)
3961 {
3962 load_flags |= FT_LOAD_NO_HINTING;
3963 iFormat &= ~GGO_UNHINTED;
3964 }
3965
3966 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3967 if (error)
3968 {
3969 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3970 IntUnLockFreeType();
3971 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3972 return GDI_ERROR;
3973 }
3974 IntUnLockFreeType();
3975
3976 FLOATOBJ_Set1(&widthRatio);
3977 if (aveWidth && potm)
3978 {
3979 // widthRatio = aveWidth * eM11 / potm->otmTextMetrics.tmAveCharWidth
3980 FLOATOBJ_SetLong(&widthRatio, aveWidth);
3981 FLOATOBJ_Mul(&widthRatio, &eM11);
3982 FLOATOBJ_DivLong(&widthRatio, potm->otmTextMetrics.tmAveCharWidth);
3983 }
3984
3985 //left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3986 FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiBearingX);
3987 FLOATOBJ_Mul(&eTemp, &widthRatio);
3988 left = FLOATOBJ_GetLong(&eTemp) & -64;
3989
3990 //right = (INT)((ft_face->glyph->metrics.horiBearingX +
3991 // ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3992 FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiBearingX * ft_face->glyph->metrics.width);
3993 FLOATOBJ_Mul(&eTemp, &widthRatio);
3994 FLOATOBJ_AddLong(&eTemp, 63);
3995 right = FLOATOBJ_GetLong(&eTemp) & -64;
3996
3997 //adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3998 FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiAdvance);
3999 FLOATOBJ_Mul(&eTemp, &widthRatio);
4000 FLOATOBJ_AddLong(&eTemp, 63);
4001 adv = FLOATOBJ_GetLong(&eTemp) >> 6;
4002
4003 lsb = left >> 6;
4004 bbx = (right - left) >> 6;
4005
4006 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
4007
4008 IntLockFreeType();
4009
4010 /* Width scaling transform */
4011 if (!FLOATOBJ_Equal1(&widthRatio))
4012 {
4013 FT_Matrix scaleMat;
4014
4015 eTemp = widthRatio;
4016 FLOATOBJ_MulLong(&eTemp, 1 << 16);
4017
4018 scaleMat.xx = FLOATOBJ_GetLong(&eTemp);
4019 scaleMat.xy = 0;
4020 scaleMat.yx = 0;
4021 scaleMat.yy = INT_TO_FIXED(1);
4022 FT_Matrix_Multiply(&scaleMat, &transMat);
4023 needsTransform = TRUE;
4024 }
4025
4026 /* World transform */
4027 {
4028 FT_Matrix ftmatrix;
4029 PMATRIX pmx = DC_pmxWorldToDevice(dc);
4030
4031 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
4032 FtMatrixFromMx(&ftmatrix, pmx);
4033
4034 if (memcmp(&ftmatrix, &identityMat, sizeof(identityMat)) != 0)
4035 {
4036 FT_Matrix_Multiply(&ftmatrix, &transMat);
4037 needsTransform = TRUE;
4038 }
4039 }
4040
4041 /* Rotation transform */
4042 if (orientation)
4043 {
4044 FT_Matrix rotationMat;
4045 DPRINT("Rotation Trans!\n");
4046 IntEscapeMatrix(&rotationMat, orientation);
4047 FT_Matrix_Multiply(&rotationMat, &transMat);
4048 needsTransform = TRUE;
4049 }
4050
4051 /* Extra transformation specified by caller */
4052 if (pmat2)
4053 {
4054 FT_Matrix extraMat;
4055 DPRINT("MAT2 Matrix Trans!\n");
4056 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
4057 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
4058 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
4059 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
4060 FT_Matrix_Multiply(&extraMat, &transMat);
4061 needsTransform = TRUE;
4062 }
4063
4064 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
4065
4066 if (!needsTransform)
4067 {
4068 DPRINT("No Need to be Transformed!\n");
4069 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4070 bottom = (ft_face->glyph->metrics.horiBearingY -
4071 ft_face->glyph->metrics.height) & -64;
4072 gm.gmCellIncX = adv;
4073 gm.gmCellIncY = 0;
4074 }
4075 else
4076 {
4077 INT xc, yc;
4078 FT_Vector vec;
4079 for (xc = 0; xc < 2; xc++)
4080 {
4081 for (yc = 0; yc < 2; yc++)
4082 {
4083 vec.x = (ft_face->glyph->metrics.horiBearingX +
4084 xc * ft_face->glyph->metrics.width);
4085 vec.y = ft_face->glyph->metrics.horiBearingY -
4086 yc * ft_face->glyph->metrics.height;
4087 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
4088 FT_Vector_Transform(&vec, &transMat);
4089 if (xc == 0 && yc == 0)
4090 {
4091 left = right = vec.x;
4092 top = bottom = vec.y;
4093 }
4094 else
4095 {
4096 if (vec.x < left) left = vec.x;
4097 else if (vec.x > right) right = vec.x;
4098 if (vec.y < bottom) bottom = vec.y;
4099 else if (vec.y > top) top = vec.y;
4100 }
4101 }
4102 }
4103 left = left & -64;
4104 right = (right + 63) & -64;
4105 bottom = bottom & -64;
4106 top = (top + 63) & -64;
4107
4108 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4109 vec.x = ft_face->glyph->metrics.horiAdvance;
4110 vec.y = 0;
4111 FT_Vector_Transform(&vec, &transMat);
4112 gm.gmCellIncX = (vec.x+63) >> 6;
4113 gm.gmCellIncY = -((vec.y+63) >> 6);
4114 }
4115 gm.gmBlackBoxX = (right - left) >> 6;
4116 gm.gmBlackBoxY = (top - bottom) >> 6;
4117 gm.gmptGlyphOrigin.x = left >> 6;
4118 gm.gmptGlyphOrigin.y = top >> 6;
4119
4120 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
4121 gm.gmCellIncX, gm.gmCellIncY,
4122 gm.gmBlackBoxX, gm.gmBlackBoxY,
4123 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
4124
4125 IntUnLockFreeType();
4126
4127
4128 if (iFormat == GGO_METRICS)
4129 {
4130 DPRINT("GGO_METRICS Exit!\n");
4131 *pgm = gm;
4132 return 1; /* FIXME */
4133 }
4134
4135 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
4136 {
4137 DPRINT1("Loaded a bitmap\n");
4138 return GDI_ERROR;
4139 }
4140
4141 switch (iFormat)
4142 {
4143 case GGO_BITMAP:
4144 {
4145 width = gm.gmBlackBoxX;
4146 height = gm.gmBlackBoxY;
4147 pitch = ((width + 31) >> 5) << 2;
4148 needed = pitch * height;
4149
4150 if (!pvBuf || !cjBuf) break;
4151 if (!needed) return GDI_ERROR; /* empty glyph */
4152 if (needed > cjBuf)
4153 return GDI_ERROR;
4154
4155 switch (ft_face->glyph->format)
4156 {
4157 case ft_glyph_format_bitmap:
4158 {
4159 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
4160 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
4161 INT h = min( height, ft_face->glyph->bitmap.rows );
4162 while (h--)
4163 {
4164 RtlCopyMemory(dst, src, w);
4165 src += ft_face->glyph->bitmap.pitch;
4166 dst += pitch;
4167 }
4168 break;
4169 }
4170
4171 case ft_glyph_format_outline:
4172 {
4173 ft_bitmap.width = width;
4174 ft_bitmap.rows = height;
4175 ft_bitmap.pitch = pitch;
4176 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
4177 ft_bitmap.buffer = pvBuf;
4178
4179 IntLockFreeType();
4180 if (needsTransform)
4181 {
4182 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4183 }
4184 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4185 /* Note: FreeType will only set 'black' bits for us. */
4186 RtlZeroMemory(pvBuf, needed);
4187 FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
4188 IntUnLockFreeType();
4189 break;
4190 }
4191
4192 default:
4193 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
4194 return GDI_ERROR;
4195 }
4196
4197 break;
4198 }
4199
4200 case GGO_GRAY2_BITMAP:
4201 case GGO_GRAY4_BITMAP:
4202 case GGO_GRAY8_BITMAP:
4203 {
4204 unsigned int mult, row, col;
4205 BYTE *start, *ptr;
4206
4207 width = gm.gmBlackBoxX;
4208 height = gm.gmBlackBoxY;
4209 pitch = (width + 3) / 4 * 4;
4210 needed = pitch * height;
4211
4212 if (!pvBuf || !cjBuf) break;
4213 if (!needed) return GDI_ERROR; /* empty glyph */
4214 if (needed > cjBuf)
4215 return GDI_ERROR;
4216
4217 switch (ft_face->glyph->format)
4218 {
4219 case ft_glyph_format_bitmap:
4220 {
4221 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
4222 INT h = min( height, ft_face->glyph->bitmap.rows );
4223 INT x;
4224 while (h--)
4225 {
4226 for (x = 0; (UINT)x < pitch; x++)
4227 {
4228 if (x < ft_face->glyph->bitmap.width)
4229 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4230 else
4231 dst[x] = 0;
4232 }
4233 src += ft_face->glyph->bitmap.pitch;
4234 dst += pitch;
4235 }
4236 break;
4237 }
4238 case ft_glyph_format_outline:
4239 {
4240 ft_bitmap.width = width;
4241 ft_bitmap.rows = height;
4242 ft_bitmap.pitch = pitch;
4243 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
4244 ft_bitmap.buffer = pvBuf;
4245
4246 IntLockFreeType();
4247 if (needsTransform)
4248 {
4249 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4250 }
4251 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4252 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
4253 FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
4254 IntUnLockFreeType();
4255
4256 if (iFormat == GGO_GRAY2_BITMAP)
4257 mult = 4;
4258 else if (iFormat == GGO_GRAY4_BITMAP)
4259 mult = 16;
4260 else if (iFormat == GGO_GRAY8_BITMAP)
4261 mult = 64;
4262 else
4263 {
4264 return GDI_ERROR;
4265 }
4266
4267 start = pvBuf;
4268 for (row = 0; row < height; row++)
4269 {
4270 ptr = start;
4271 for (col = 0; col < width; col++, ptr++)
4272 {
4273 *ptr = (((int)*ptr) * mult + 128) / 256;
4274 }
4275 start += pitch;
4276 }
4277
4278 break;
4279 }
4280 default:
4281 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
4282 return GDI_ERROR;
4283 }
4284
4285 break;
4286 }
4287
4288 case GGO_NATIVE:
4289 {
4290 FT_Outline *outline = &ft_face->glyph->outline;
4291
4292 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
4293
4294 IntLockFreeType();
4295 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
4296
4297 needed = get_native_glyph_outline(outline, cjBuf, NULL);
4298
4299 if (!pvBuf || !cjBuf)
4300 {
4301 IntUnLockFreeType();
4302 break;
4303 }
4304 if (needed > cjBuf)
4305 {
4306 IntUnLockFreeType();
4307 return GDI_ERROR;
4308 }
4309 get_native_glyph_outline(outline, cjBuf, pvBuf);
4310 IntUnLockFreeType();
4311 break;
4312 }
4313
4314 case GGO_BEZIER:
4315 {
4316 FT_Outline *outline = &ft_face->glyph->outline;
4317 if (cjBuf == 0) pvBuf = NULL;
4318
4319 if (needsTransform && pvBuf)
4320 {
4321 IntLockFreeType();
4322 FT_Outline_Transform(outline, &transMat);
4323 IntUnLockFreeType();
4324 }
4325 needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
4326
4327 if (!pvBuf || !cjBuf)
4328 break;
4329 if (needed > cjBuf)
4330 return GDI_ERROR;
4331
4332 get_bezier_glyph_outline(outline, cjBuf, pvBuf);
4333 break;
4334 }
4335
4336 default:
4337 DPRINT1("Unsupported format %u\n", iFormat);
4338 return GDI_ERROR;
4339 }
4340
4341 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
4342 *pgm = gm;
4343 return needed;
4344 }
4345
4346 BOOL
4347 FASTCALL
4348 TextIntGetTextExtentPoint(PDC dc,
4349 PTEXTOBJ TextObj,
4350 LPCWSTR String,
4351 INT Count,
4352 ULONG MaxExtent,
4353 LPINT Fit,
4354 LPINT Dx,
4355 LPSIZE Size,
4356 FLONG fl)
4357 {
4358 PFONTGDI FontGDI;
4359 FT_Face face;
4360 FT_GlyphSlot glyph;
4361 FT_BitmapGlyph realglyph;
4362 INT error, glyph_index, i, previous;
4363 ULONGLONG TotalWidth64 = 0;
4364 BOOL use_kerning;
4365 FT_Render_Mode RenderMode;
4366 BOOLEAN Render;
4367 PMATRIX pmxWorldToDevice;
4368 LOGFONTW *plf;
4369 BOOL EmuBold, EmuItalic;
4370 LONG ascender, descender;
4371
4372 FontGDI = ObjToGDI(TextObj->Font, FONT);
4373
4374 face = FontGDI->SharedFace->Face;
4375 if (NULL != Fit)
4376 {
4377 *Fit = 0;
4378 }
4379
4380 IntLockFreeType();
4381
4382 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
4383
4384 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4385 EmuBold = EMUBOLD_NEEDED(FontGDI->OriginalWeight, plf->lfWeight);
4386 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
4387
4388 Render = IntIsFontRenderingEnabled();
4389 if (Render)
4390 RenderMode = IntGetFontRenderMode(plf);
4391 else
4392 RenderMode = FT_RENDER_MODE_MONO;
4393
4394 /* Get the DC's world-to-device transformation matrix */
4395 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
4396 FtSetCoordinateTransform(face, pmxWorldToDevice);
4397
4398 use_kerning = FT_HAS_KERNING(face);
4399 previous = 0;
4400
4401 for (i = 0; i < Count; i++)
4402 {
4403 glyph_index = get_glyph_index_flagged(face, *String, GTEF_INDICES, fl);
4404
4405 if (EmuBold || EmuItalic)
4406 realglyph = NULL;
4407 else
4408 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
4409 RenderMode, pmxWorldToDevice);
4410
4411 if (EmuBold || EmuItalic || !realglyph)
4412 {
4413 if (EmuItalic)
4414 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_BITMAP);
4415 else
4416 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
4417 if (error)
4418 {
4419 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
4420 break;
4421 }
4422
4423 glyph = face->glyph;
4424 if (EmuBold || EmuItalic)
4425 {
4426 if (EmuBold)
4427 FT_GlyphSlot_Embolden(glyph);
4428 if (EmuItalic)
4429 FT_GlyphSlot_Oblique(glyph);
4430 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
4431 }
4432 else
4433 {
4434 realglyph = ftGdiGlyphCacheSet(face,
4435 glyph_index,
4436 plf->lfHeight,
4437 pmxWorldToDevice,
4438 glyph,
4439 RenderMode);
4440 }
4441
4442 if (!realglyph)
4443 {
4444 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
4445 break;
4446 }
4447 }
4448
4449 /* Retrieve kerning distance */
4450 if (use_kerning && previous && glyph_index)
4451 {
4452 FT_Vector delta;
4453 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
4454 TotalWidth64 += delta.x;
4455 }
4456
4457 TotalWidth64 += realglyph->root.advance.x >> 10;
4458
4459 if (((TotalWidth64 + 32) >> 6) <= MaxExtent && NULL != Fit)
4460 {
4461 *Fit = i + 1;
4462 }
4463 if (NULL != Dx)
4464 {
4465 Dx[i] = (TotalWidth64 + 32) >> 6;
4466 }
4467
4468 /* Bold and italic do not use the cache */
4469 if (EmuBold || EmuItalic)
4470 {
4471 FT_Done_Glyph((FT_Glyph)realglyph);
4472 }
4473
4474 previous = glyph_index;
4475 String++;
4476 }
4477 ASSERT(FontGDI->Magic == FONTGDI_MAGIC);
4478 ascender = FontGDI->tmAscent; /* Units above baseline */
4479 descender = FontGDI->tmDescent; /* Units below baseline */
4480 IntUnLockFreeType();
4481
4482 Size->cx = (TotalWidth64 + 32) >> 6;
4483 Size->cy = ascender + descender;
4484
4485 return TRUE;
4486 }
4487
4488
4489 INT
4490 FASTCALL
4491 ftGdiGetTextCharsetInfo(
4492 PDC Dc,
4493 LPFONTSIGNATURE lpSig,
4494 DWORD dwFlags)
4495 {
4496 PDC_ATTR pdcattr;
4497 UINT Ret = DEFAULT_CHARSET;
4498 INT i;
4499 HFONT hFont;
4500 PTEXTOBJ TextObj;
4501 PFONTGDI FontGdi;
4502 FONTSIGNATURE fs;
4503 TT_OS2 *pOS2;
4504 FT_Face Face;
4505 CHARSETINFO csi;
4506 DWORD cp, fs0;
4507 USHORT usACP, usOEM;
4508
4509 pdcattr = Dc->pdcattr;
4510 hFont = pdcattr->hlfntNew;
4511 TextObj = RealizeFontInit(hFont);
4512
4513 if (!TextObj)
4514 {
4515 EngSetLastError(ERROR_INVALID_HANDLE);
4516 return Ret;
4517 }
4518 FontGdi = ObjToGDI(TextObj->Font, FONT);
4519 Face = FontGdi->SharedFace->Face;
4520 TEXTOBJ_UnlockText(TextObj);
4521
4522 memset(&fs, 0, sizeof(FONTSIGNATURE));
4523 IntLockFreeType();
4524 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4525 if (NULL != pOS2)
4526 {
4527 fs.fsCsb[0] = pOS2->ulCodePageRange1;
4528 fs.fsCsb[1] = pOS2->ulCodePageRange2;
4529 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
4530 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
4531 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
4532 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
4533 if (pOS2->version == 0)
4534 {
4535 FT_UInt dummy;
4536
4537 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
4538 fs.fsCsb[0] |= FS_LATIN1;
4539 else
4540 fs.fsCsb[0] |= FS_SYMBOL;
4541 }
4542 }
4543 pOS2 = NULL;
4544 IntUnLockFreeType();
4545 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
4546 if (fs.fsCsb[0] == 0)
4547 { /* Let's see if we can find any interesting cmaps */
4548 for (i = 0; i < Face->num_charmaps; i++)
4549 {
4550 switch (Face->charmaps[i]->encoding)
4551 {
4552 case FT_ENCODING_UNICODE:
4553 case FT_ENCODING_APPLE_ROMAN:
4554 fs.fsCsb[0] |= FS_LATIN1;
4555 break;
4556 case FT_ENCODING_MS_SYMBOL:
4557 fs.fsCsb[0] |= FS_SYMBOL;
4558 break;
4559 default:
4560 break;
4561 }
4562 }
4563 }
4564 if (lpSig)
4565 {
4566 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
4567 }
4568
4569 RtlGetDefaultCodePage(&usACP, &usOEM);
4570 cp = usACP;
4571
4572 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
4573 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
4574 {
4575 DPRINT("Hit 1\n");
4576 Ret = csi.ciCharset;
4577 goto Exit;
4578 }
4579
4580 for (i = 0; i < MAXTCIINDEX; i++)
4581 {
4582 fs0 = 1L << i;
4583 if (fs.fsCsb[0] & fs0)
4584 {
4585 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
4586 {
4587 // *cp = csi.ciACP;
4588 DPRINT("Hit 2\n");
4589 Ret = csi.ciCharset;
4590 goto Exit;
4591 }
4592 else
4593 DPRINT1("TCI failing on %x\n", fs0);
4594 }
4595 }
4596 Exit:
4597 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
4598 return (MAKELONG(csi.ciACP, csi.ciCharset));
4599 }
4600
4601
4602 DWORD
4603 FASTCALL
4604 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
4605 {
4606 DWORD size = 0;
4607 DWORD num_ranges = 0;
4608 FT_Face face = Font->SharedFace->Face;
4609
4610 if (face->charmap->encoding == FT_ENCODING_UNICODE)
4611 {
4612 FT_UInt glyph_code = 0;
4613 FT_ULong char_code, char_code_prev;
4614
4615 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
4616
4617 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4618 face->num_glyphs, glyph_code, char_code);
4619
4620 if (!glyph_code) return 0;
4621
4622 if (glyphset)
4623 {
4624 glyphset->ranges[0].wcLow = (USHORT)char_code;
4625 glyphset->ranges[0].cGlyphs = 0;
4626 glyphset->cGlyphsSupported = 0;
4627 }
4628
4629 num_ranges = 1;
4630 while (glyph_code)
4631 {
4632 if (char_code < char_code_prev)
4633 {
4634 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
4635 return 0;
4636 }
4637 if (char_code - char_code_prev > 1)
4638 {
4639 num_ranges++;
4640 if (glyphset)
4641 {
4642 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4643 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
4644 glyphset->cGlyphsSupported++;
4645 }
4646 }
4647 else if (glyphset)
4648 {
4649 glyphset->ranges[num_ranges - 1].cGlyphs++;
4650 glyphset->cGlyphsSupported++;
4651 }
4652 char_code_prev = char_code;
4653 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
4654 }
4655 }
4656 else
4657 DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
4658
4659 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4660 if (glyphset)
4661 {
4662 glyphset->cbThis = size;
4663 glyphset->cRanges = num_ranges;
4664 glyphset->flAccel = 0;
4665 }
4666 return size;
4667 }
4668
4669
4670 BOOL
4671 FASTCALL
4672 ftGdiGetTextMetricsW(
4673 HDC hDC,
4674 PTMW_INTERNAL ptmwi)
4675 {
4676 PDC dc;
4677 PDC_ATTR pdcattr;
4678 PTEXTOBJ TextObj;
4679 PFONTGDI FontGDI;
4680 FT_Face Face;
4681 TT_OS2 *pOS2;
4682 TT_HoriHeader *pHori;
4683 FT_WinFNT_HeaderRec Win;
4684 ULONG Error;
4685 NTSTATUS Status = STATUS_SUCCESS;
4686 LOGFONTW *plf;
4687
4688 if (!ptmwi)
4689 {
4690 EngSetLastError(STATUS_INVALID_PARAMETER);
4691 return FALSE;
4692 }
4693
4694 if (!(dc = DC_LockDc(hDC)))
4695 {
4696 EngSetLastError(ERROR_INVALID_HANDLE);
4697 return FALSE;
4698 }
4699 pdcattr = dc->pdcattr;
4700 TextObj = RealizeFontInit(pdcattr->hlfntNew);
4701 if (NULL != TextObj)
4702 {
4703 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4704 FontGDI = ObjToGDI(TextObj->Font, FONT);
4705
4706 Face = FontGDI->SharedFace->Face;
4707
4708 IntLockFreeType();
4709 Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
4710 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
4711 IntUnLockFreeType();
4712
4713 if (0 != Error)
4714 {
4715 DPRINT1("Error in setting pixel sizes: %u\n", Error);
4716 Status = STATUS_UNSUCCESSFUL;
4717 }
4718 else
4719 {
4720 FT_Face Face = FontGDI->SharedFace->Face;
4721 Status = STATUS_SUCCESS;
4722
4723 IntLockFreeType();
4724 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4725 if (NULL == pOS2)
4726 {
4727 DPRINT1("Can't find OS/2 table - not TT font?\n");
4728 Status = STATUS_INTERNAL_ERROR;
4729 }
4730
4731 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
4732 if (NULL == pHori)
4733 {
4734 DPRINT1("Can't find HHEA table - not TT font?\n");
4735 Status = STATUS_INTERNAL_ERROR;
4736 }
4737
4738 Error = FT_Get_WinFNT_Header(Face, &Win);
4739
4740 if (NT_SUCCESS(Status) || !Error)
4741 {
4742 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
4743
4744 /* FIXME: Fill Diff member */
4745 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
4746 }
4747
4748 IntUnLockFreeType();
4749 }
4750 TEXTOBJ_UnlockText(TextObj);
4751 }
4752 else
4753 {
4754 Status = STATUS_INVALID_HANDLE;
4755 }
4756 DC_UnlockDc(dc);
4757
4758 if (!NT_SUCCESS(Status))
4759 {
4760 SetLastNtError(Status);
4761 return FALSE;
4762 }
4763 return TRUE;
4764 }
4765
4766 DWORD
4767 FASTCALL
4768 ftGdiGetFontData(
4769 PFONTGDI FontGdi,
4770 DWORD Table,
4771 DWORD Offset,
4772 PVOID Buffer,
4773 DWORD Size)
4774 {
4775 DWORD Result = GDI_ERROR;
4776 FT_Face Face = FontGdi->SharedFace->Face;
4777
4778 IntLockFreeType();
4779
4780 if (FT_IS_SFNT(Face))
4781 {
4782 if (Table)
4783 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
4784 (Table << 8 & 0xFF0000);
4785
4786 if (!Buffer) Size = 0;
4787
4788 if (Buffer && Size)
4789 {
4790 FT_Error Error;
4791 FT_ULong Needed = 0;
4792
4793 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
4794
4795 if ( !Error && Needed < Size) Size = Needed;
4796 }
4797 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
4798 Result = Size;
4799 }
4800
4801 IntUnLockFreeType();
4802
4803 return Result;
4804 }
4805
4806 #define GOT_PENALTY(name, value) Penalty += (value)
4807
4808 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
4809 static UINT
4810 GetFontPenalty(const LOGFONTW * LogFont,
4811 const OUTLINETEXTMETRICW * Otm,
4812 const char * style_name)
4813 {
4814 ULONG Penalty = 0;
4815 BYTE Byte;
4816 LONG Long;
4817 BOOL fNeedScaling = FALSE;
4818 const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
4819 const TEXTMETRICW * TM = &Otm->otmTextMetrics;
4820 WCHAR* ActualNameW;
4821
4822 ASSERT(Otm);
4823 ASSERT(LogFont);
4824
4825 /* FIXME: IntSizeSynth Penalty 20 */
4826 /* FIXME: SmallPenalty Penalty 1 */
4827 /* FIXME: FaceNameSubst Penalty 500 */
4828
4829 Byte = LogFont->lfCharSet;
4830
4831 if (Byte != TM->tmCharSet)
4832 {
4833 if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
4834 {
4835 /* CharSet Penalty 65000 */
4836 /* Requested charset does not match the candidate's. */
4837 GOT_PENALTY("CharSet", 65000);
4838 }
4839 else
4840 {
4841 if (UserCharSet != TM->tmCharSet)
4842 {
4843 /* UNDOCUMENTED: Not user language */
4844 GOT_PENALTY("UNDOCUMENTED:NotUserLanguage", 100);
4845
4846 if (ANSI_CHARSET != TM->tmCharSet)
4847 {
4848 /* UNDOCUMENTED: Not ANSI charset */
4849 GOT_PENALTY("UNDOCUMENTED:NotAnsiCharSet", 100);
4850 }
4851 }
4852 }
4853 }
4854
4855 Byte = LogFont->lfOutPrecision;
4856 switch (Byte)
4857 {
4858 case OUT_DEFAULT_PRECIS:
4859 /* nothing to do */
4860 break;
4861 case OUT_DEVICE_PRECIS:
4862 if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
4863 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
4864 {
4865 /* OutputPrecision Penalty 19000 */
4866 /* Requested OUT_STROKE_PRECIS, but the device can't do it
4867 or the candidate is not a vector font. */
4868 GOT_PENALTY("OutputPrecision", 19000);
4869 }
4870 break;
4871 default:
4872 if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
4873 {
4874 /* OutputPrecision Penalty 19000 */
4875 /* Or OUT_STROKE_PRECIS not requested, and the candidate
4876 is a vector font that requires GDI support. */
4877 GOT_PENALTY("OutputPrecision", 19000);
4878 }
4879 break;
4880 }
4881
4882 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4883 if (Byte == DEFAULT_PITCH)
4884 Byte = VARIABLE_PITCH;
4885 if (Byte == FIXED_PITCH)
4886 {
4887 if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
4888 {
4889 /* FixedPitch Penalty 15000 */
4890 /* Requested a fixed pitch font, but the candidate is a
4891 variable pitch font. */
4892 GOT_PENALTY("FixedPitch", 15000);
4893 }
4894 }
4895 if (Byte == VARIABLE_PITCH)
4896 {
4897 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4898 {
4899 /* PitchVariable Penalty 350 */
4900 /* Requested a variable pitch font, but the candidate is not a
4901 variable pitch font. */
4902 GOT_PENALTY("PitchVariable", 350);
4903 }
4904 }
4905
4906 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4907 if (Byte == DEFAULT_PITCH)
4908 {
4909 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4910 {
4911 /* DefaultPitchFixed Penalty 1 */
4912 /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
4913 GOT_PENALTY("DefaultPitchFixed", 1);
4914 }
4915 }
4916
4917 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
4918
4919 if (LogFont->lfFaceName[0] != UNICODE_NULL)
4920 {
4921 BOOL Found = FALSE;
4922
4923 /* localized family name */
4924 if (!Found)
4925 {
4926 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4927 }
4928 /* localized full name */
4929 if (!Found)
4930 {
4931 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
4932 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4933 }
4934 if (!Found)
4935 {
4936 /* FaceName Penalty 10000 */
4937 /* Requested a face name, but the candidate's face name
4938 does not match. */
4939 GOT_PENALTY("FaceName", 10000);
4940 }
4941 }
4942
4943 Byte = (LogFont->lfPitchAndFamily & 0xF0);
4944 if (Byte != FF_DONTCARE)
4945 {
4946 if (Byte != (TM->tmPitchAndFamily & 0xF0))
4947 {
4948 /* Family Penalty 9000 */
4949 /* Requested a family, but the candidate's family is different. */
4950 GOT_PENALTY("Family", 9000);
4951 }
4952 }
4953
4954 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
4955 {
4956 /* FamilyUnknown Penalty 8000 */
4957 /* Requested a family, but the candidate has no family. */
4958 GOT_PENALTY("FamilyUnknown", 8000);
4959 }
4960
4961 /* Is the candidate a non-vector font? */
4962 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4963 {
4964 /* Is lfHeight specified? */
4965 if (LogFont->lfHeight != 0)
4966 {
4967 if (labs(LogFont->lfHeight) < TM->tmHeight)
4968 {
4969 /* HeightBigger Penalty 600 */
4970 /* The candidate is a nonvector font and is bigger than the
4971 requested height. */
4972 GOT_PENALTY("HeightBigger", 600);
4973 /* HeightBiggerDifference Penalty 150 */
4974 /* The candidate is a raster font and is larger than the
4975 requested height. Penalty * height difference */
4976 GOT_PENALTY("HeightBiggerDifference", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)));
4977
4978 fNeedScaling = TRUE;
4979 }
4980 if (TM->tmHeight < labs(LogFont->lfHeight))
4981 {
4982 /* HeightSmaller Penalty 150 */
4983 /* The candidate is a raster font and is smaller than the
4984 requested height. Penalty * height difference */
4985 GOT_PENALTY("HeightSmaller", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)));
4986
4987 fNeedScaling = TRUE;
4988 }
4989 }
4990 }
4991
4992 switch (LogFont->lfPitchAndFamily & 0xF0)
4993 {
4994 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4995 switch (TM->tmPitchAndFamily & 0xF0)
4996 {
4997 case FF_DECORATIVE: case FF_SCRIPT:
4998 /* FamilyUnlikely Penalty 50 */
4999 /* Requested a roman/modern/swiss family, but the
5000 candidate is decorative/script. */
5001 GOT_PENALTY("FamilyUnlikely", 50);
5002 break;
5003 default:
5004 break;
5005 }
5006 break;
5007 case FF_DECORATIVE: case FF_SCRIPT:
5008 switch (TM->tmPitchAndFamily & 0xF0)
5009 {
5010 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
5011 /* FamilyUnlikely Penalty 50 */
5012 /* Or requested decorative/script, and the candidate is
5013 roman/modern/swiss. */
5014 GOT_PENALTY("FamilyUnlikely", 50);
5015 break;
5016 default:
5017 break;
5018 }
5019 default:
5020 break;
5021 }
5022
5023 if (LogFont->lfWidth != 0)
5024 {
5025 if (LogFont->lfWidth != TM->tmAveCharWidth)
5026 {
5027 /* Width Penalty 50 */
5028 /* Requested a nonzero width, but the candidate's width
5029 doesn't match. Penalty * width difference */
5030 GOT_PENALTY("Width", 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth));
5031
5032 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
5033 fNeedScaling = TRUE;
5034 }
5035 }
5036
5037 if (fNeedScaling)
5038 {
5039 /* SizeSynth Penalty 50 */
5040 /* The candidate is a raster font that needs scaling by GDI. */
5041 GOT_PENALTY("SizeSynth", 50);
5042 }
5043
5044 if (!LogFont->lfItalic && TM->tmItalic)
5045 {
5046 /* Italic Penalty 4 */
5047 /* Requested font and candidate font do not agree on italic status,
5048 and the desired result cannot be simulated. */
5049 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
5050 GOT_PENALTY("Italic", 40);
5051 }
5052 else if (LogFont->lfItalic && !TM->tmItalic)
5053 {
5054 /* ItalicSim Penalty 1 */
5055 /* Requested italic font but the candidate is not italic,
5056 although italics can be simulated. */
5057 GOT_PENALTY("ItalicSim", 1);
5058 }
5059
5060 if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
5061 {
5062 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
5063 {
5064 /* NotTrueType Penalty 4 */
5065 /* Requested OUT_TT_PRECIS, but the candidate is not a
5066 TrueType font. */
5067 GOT_PENALTY("NotTrueType", 4);
5068 }
5069 }
5070
5071 Long = LogFont->lfWeight;
5072 if (LogFont->lfWeight == FW_DONTCARE)
5073 Long = FW_NORMAL;
5074 if (Long != TM->tmWeight)
5075 {
5076 /* Weight Penalty 3 */
5077 /* The candidate's weight does not match the requested weight.
5078 Penalty * (weight difference/10) */
5079 GOT_PENALTY("Weight", 3 * (labs(Long - TM->tmWeight) / 10));
5080 }
5081
5082 if (!LogFont->lfUnderline && TM->tmUnderlined)
5083 {
5084 /* Underline Penalty 3 */
5085 /* Requested font has no underline, but the candidate is
5086 underlined. */
5087 GOT_PENALTY("Underline", 3);
5088 }
5089
5090 if (!LogFont->lfStrikeOut && TM->tmStruckOut)
5091 {
5092 /* StrikeOut Penalty 3 */
5093 /* Requested font has no strike-out, but the candidate is
5094 struck out. */
5095 GOT_PENALTY("StrikeOut", 3);
5096 }
5097
5098 /* Is the candidate a non-vector font? */
5099 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
5100 {
5101 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
5102 {
5103 /* VectorHeightSmaller Penalty 2 */
5104 /* Candidate is a vector font that is smaller than the
5105 requested height. Penalty * height difference */
5106 GOT_PENALTY("VectorHeightSmaller", 2 * labs(TM->tmHeight - LogFont->lfHeight));
5107 }
5108 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
5109 {
5110 /* VectorHeightBigger Penalty 1 */
5111 /* Candidate is a vector font that is bigger than the
5112 requested height. Penalty * height difference */
5113 GOT_PENALTY("VectorHeightBigger", 1 * labs(TM->tmHeight - LogFont->lfHeight));
5114 }
5115 }
5116
5117 if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
5118 {
5119 /* DeviceFavor Penalty 2 */
5120 /* Extra penalty for all nondevice fonts. */
5121 GOT_PENALTY("DeviceFavor", 2);
5122 }
5123
5124 if (TM->tmAveCharWidth >= 5 && TM->tmHeight >= 5)
5125 {
5126 if (TM->tmAveCharWidth / TM->tmHeight >= 3)
5127 {
5128 /* Aspect Penalty 30 */
5129 /* The aspect rate is >= 3. It seems like a bad font. */
5130 GOT_PENALTY("Aspect", ((TM->tmAveCharWidth / TM->tmHeight) - 2) * 30);
5131 }
5132 else if (TM->tmHeight / TM->tmAveCharWidth >= 3)
5133 {
5134 /* Aspect Penalty 30 */
5135 /* The aspect rate is >= 3. It seems like a bad font. */
5136 GOT_PENALTY("Aspect", ((TM->tmHeight / TM->tmAveCharWidth) - 2) * 30);
5137 }
5138 }
5139
5140 if (Penalty < 200)
5141 {
5142 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
5143 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
5144 "tmCharSet:%d, tmWeight:%ld\n",
5145 Penalty, LogFont->lfFaceName, ActualNameW,
5146 LogFont->lfCharSet, LogFont->lfWeight,
5147 TM->tmCharSet, TM->tmWeight);
5148 }
5149
5150 return Penalty; /* success */
5151 }
5152
5153 #undef GOT_PENALTY
5154
5155 static __inline VOID
5156 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
5157 const LOGFONTW *LogFont,
5158 const PLIST_ENTRY Head)
5159 {
5160 ULONG Penalty;
5161 PLIST_ENTRY Entry;
5162 PFONT_ENTRY CurrentEntry;
5163 FONTGDI *FontGDI;
5164 OUTLINETEXTMETRICW *Otm = NULL;
5165 UINT OtmSize, OldOtmSize = 0;
5166 FT_Face Face;
5167
5168 ASSERT(FontObj);
5169 ASSERT(MatchPenalty);
5170 ASSERT(LogFont);
5171 ASSERT(Head);
5172
5173 /* Start with a pretty big buffer */
5174 OldOtmSize = 0x200;
5175 Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
5176
5177 /* get the FontObj of lowest penalty */
5178 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
5179 {
5180 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
5181
5182 FontGDI = CurrentEntry->Font;
5183 ASSERT(FontGDI);
5184 Face = FontGDI->SharedFace->Face;
5185
5186 /* get text metrics */
5187 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
5188 if (OtmSize > OldOtmSize)
5189 {
5190 if (Otm)
5191 ExFreePoolWithTag(Otm, GDITAG_TEXT);
5192 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
5193 }
5194
5195 /* update FontObj if lowest penalty */
5196 if (Otm)
5197 {
5198 IntLockFreeType();
5199 IntRequestFontSize(NULL, FontGDI, LogFont->lfWidth, LogFont->lfHeight);
5200 IntUnLockFreeType();
5201
5202 OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
5203 if (!OtmSize)
5204 continue;
5205
5206 OldOtmSize = OtmSize;
5207
5208 Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
5209 if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
5210 {
5211 *FontObj = GDIToObj(FontGDI, FONT);
5212 *MatchPenalty = Penalty;
5213 }
5214 }
5215 }
5216
5217 if (Otm)
5218 ExFreePoolWithTag(Otm, GDITAG_TEXT);
5219 }
5220
5221 static
5222 VOID
5223 FASTCALL
5224 IntFontType(PFONTGDI Font)
5225 {
5226 PS_FontInfoRec psfInfo;
5227 FT_ULong tmp_size = 0;
5228 FT_Face Face = Font->SharedFace->Face;
5229
5230 ASSERT_FREETYPE_LOCK_NOT_HELD();
5231 IntLockFreeType();
5232
5233 if (FT_HAS_MULTIPLE_MASTERS(Face))
5234 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
5235 if (FT_HAS_VERTICAL(Face))
5236 Font->FontObj.flFontType |= FO_VERT_FACE;
5237 if (!FT_IS_SCALABLE(Face))
5238 Font->FontObj.flFontType |= FO_TYPE_RASTER;
5239 if (FT_IS_SFNT(Face))
5240 {
5241 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
5242 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
5243 Font->FontObj.flFontType |= FO_POSTSCRIPT;
5244 }
5245 if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
5246 {
5247 Font->FontObj.flFontType |= FO_POSTSCRIPT;
5248 }
5249 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
5250 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
5251 {
5252 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
5253 }
5254
5255 IntUnLockFreeType();
5256 }
5257
5258 static BOOL
5259 MatchFontName(PSHARED_FACE SharedFace, LPCWSTR lfFaceName, FT_UShort NameID, FT_UShort LangID)
5260 {
5261 NTSTATUS Status;
5262 UNICODE_STRING Name1, Name2;
5263
5264 if (lfFaceName[0] == UNICODE_NULL)
5265 return FALSE;
5266
5267 RtlInitUnicodeString(&Name1, lfFaceName);
5268
5269 RtlInitUnicodeString(&Name2, NULL);
5270 Status = IntGetFontLocalizedName(&Name2, SharedFace, NameID, LangID);
5271
5272 if (NT_SUCCESS(Status))
5273 {
5274 if (RtlCompareUnicodeString(&Name1, &Name2, TRUE) == 0)
5275 {
5276 RtlFreeUnicodeString(&Name2);
5277 return TRUE;
5278 }
5279
5280 RtlFreeUnicodeString(&Name2);
5281 }
5282
5283 return FALSE;
5284 }
5285
5286 static BOOL
5287 MatchFontNames(PSHARED_FACE SharedFace, LPCWSTR lfFaceName)
5288 {
5289 if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, LANG_ENGLISH) ||
5290 MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, LANG_ENGLISH))
5291 {
5292 return TRUE;
5293 }
5294 if (PRIMARYLANGID(gusLanguageID) != LANG_ENGLISH)
5295 {
5296 if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, gusLanguageID) ||
5297 MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, gusLanguageID))
5298 {
5299 return TRUE;
5300 }
5301 }
5302 return FALSE;
5303 }
5304
5305 NTSTATUS
5306 FASTCALL
5307 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
5308 {
5309 NTSTATUS Status = STATUS_SUCCESS;
5310 PTEXTOBJ TextObj;
5311 PPROCESSINFO Win32Process;
5312 ULONG MatchPenalty;
5313 LOGFONTW *pLogFont;
5314 LOGFONTW SubstitutedLogFont;
5315
5316 if (!pTextObj)
5317 {
5318 TextObj = TEXTOBJ_LockText(FontHandle);
5319 if (NULL == TextObj)
5320 {
5321 return STATUS_INVALID_HANDLE;
5322 }
5323
5324 if (TextObj->fl & TEXTOBJECT_INIT)
5325 {
5326 TEXTOBJ_UnlockText(TextObj);
5327 return STATUS_SUCCESS;
5328 }
5329 }
5330 else
5331 {
5332 TextObj = pTextObj;
5333 }
5334
5335 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5336
5337 /* substitute */
5338 SubstitutedLogFont = *pLogFont;
5339 DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
5340 SubstituteFontRecurse(&SubstitutedLogFont);
5341 DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
5342
5343 MatchPenalty = 0xFFFFFFFF;
5344 TextObj->Font = NULL;
5345
5346 Win32Process = PsGetCurrentProcessWin32Process();
5347
5348 /* Search private fonts */
5349 IntLockProcessPrivateFonts(Win32Process);
5350 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
5351 &Win32Process->PrivateFontListHead);
5352 IntUnLockProcessPrivateFonts(Win32Process);
5353
5354 /* Search system fonts */
5355 IntLockGlobalFonts();
5356 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
5357 &g_FontListHead);
5358 IntUnLockGlobalFonts();
5359
5360 if (NULL == TextObj->Font)
5361 {
5362 DPRINT1("Request font %S not found, no fonts loaded at all\n",
5363 pLogFont->lfFaceName);
5364 Status = STATUS_NOT_FOUND;
5365 }
5366 else
5367 {
5368 UNICODE_STRING Name;
5369 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
5370 PSHARED_FACE SharedFace = FontGdi->SharedFace;
5371
5372 IntLockFreeType();
5373 IntRequestFontSize(NULL, FontGdi, pLogFont->lfWidth, pLogFont->lfHeight);
5374 IntUnLockFreeType();
5375
5376 TextObj->TextFace[0] = UNICODE_NULL;
5377 if (MatchFontNames(SharedFace, SubstitutedLogFont.lfFaceName))
5378 {
5379 RtlStringCchCopyW(TextObj->TextFace, _countof(TextObj->TextFace), pLogFont->lfFaceName);
5380 }
5381 else
5382 {
5383 RtlInitUnicodeString(&Name, NULL);
5384 Status = IntGetFontLocalizedName(&Name, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
5385 if (NT_SUCCESS(Status))
5386 {
5387 /* truncated copy */
5388 IntUnicodeStringToBuffer(TextObj->TextFace, sizeof(TextObj->TextFace), &Name);
5389 RtlFreeUnicodeString(&Name);
5390 }
5391 }
5392
5393 // Need hdev, when freetype is loaded need to create DEVOBJ for
5394 // Consumer and Producer.
5395 TextObj->Font->iUniq = 1; // Now it can be cached.
5396 IntFontType(FontGdi);
5397 FontGdi->flType = TextObj->Font->flFontType;
5398 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
5399 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
5400 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
5401 if (pLogFont->lfWeight != FW_DONTCARE)
5402 FontGdi->RequestWeight = pLogFont->lfWeight;
5403 else
5404 FontGdi->RequestWeight = FW_NORMAL;
5405
5406 TextObj->fl |= TEXTOBJECT_INIT;
5407 Status = STATUS_SUCCESS;
5408 }
5409
5410 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
5411
5412 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
5413
5414 return Status;
5415 }
5416
5417
5418 static
5419 BOOL
5420 FASTCALL
5421 IntGetFullFileName(
5422 POBJECT_NAME_INFORMATION NameInfo,
5423 ULONG Size,
5424 PUNICODE_STRING FileName)
5425 {
5426 NTSTATUS Status;
5427 OBJECT_ATTRIBUTES ObjectAttributes;
5428 HANDLE hFile;
5429 IO_STATUS_BLOCK IoStatusBlock;
5430 ULONG Desired;
5431
5432 InitializeObjectAttributes(&ObjectAttributes,
5433 FileName,
5434 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
5435 NULL,
5436 NULL);
5437
5438 Status = ZwOpenFile(
5439 &hFile,
5440 0, // FILE_READ_ATTRIBUTES,
5441 &ObjectAttributes,
5442 &IoStatusBlock,
5443 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5444 0);
5445
5446 if (!NT_SUCCESS(Status))
5447 {
5448 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
5449 return FALSE;
5450 }
5451
5452 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
5453 ZwClose(hFile);
5454 if (!NT_SUCCESS(Status))
5455 {
5456 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
5457 return FALSE;
5458 }
5459
5460 return TRUE;
5461 }
5462
5463 static BOOL
5464 EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2)
5465 {
5466 const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
5467 const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
5468 const LOGFONTW *plf1 = &pLog1->elfLogFont;
5469 const LOGFONTW *plf2 = &pLog2->elfLogFont;
5470
5471 if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0)
5472 {
5473 return FALSE;
5474 }
5475
5476 if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0)
5477 {
5478 return FALSE;
5479 }
5480
5481 return TRUE;
5482 }
5483
5484 static VOID
5485 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
5486 {
5487 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
5488 if (FamInfo->EnumLogFontEx.elfStyle[0] &&
5489 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
5490 {
5491 wcscat(psz, L" ");
5492 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
5493 }
5494 }
5495
5496 BOOL
5497 FASTCALL
5498 IntGdiGetFontResourceInfo(
5499 PUNICODE_STRING FileName,
5500 PVOID pBuffer,
5501 DWORD *pdwBytes,
5502 DWORD dwType)
5503 {
5504 UNICODE_STRING EntryFileName;
5505 POBJECT_NAME_INFORMATION NameInfo1 = NULL, NameInfo2 = NULL;
5506 PLIST_ENTRY ListEntry;
5507 PFONT_ENTRY FontEntry;
5508 ULONG Size, i, Count;
5509 LPBYTE pbBuffer;
5510 BOOL IsEqual;
5511 FONTFAMILYINFO *FamInfo;
5512 const ULONG MaxFamInfo = 64;
5513 const ULONG MAX_FAM_INFO_BYTES = sizeof(FONTFAMILYINFO) * MaxFamInfo;
5514 BOOL bSuccess;
5515 const ULONG NAMEINFO_SIZE = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
5516
5517 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
5518
5519 do
5520 {
5521 /* Create buffer for full path name */
5522 NameInfo1 = ExAllocatePoolWithTag(PagedPool, NAMEINFO_SIZE, TAG_FINF);
5523 if (!NameInfo1)
5524 break;
5525
5526 /* Get the full path name */
5527 if (!IntGetFullFileName(NameInfo1, NAMEINFO_SIZE, FileName))
5528 break;
5529
5530 /* Create a buffer for the entries' names */
5531 NameInfo2 = ExAllocatePoolWithTag(PagedPool, NAMEINFO_SIZE, TAG_FINF);
5532 if (!NameInfo2)
5533 break;
5534
5535 FamInfo = ExAllocatePoolWithTag(PagedPool, MAX_FAM_INFO_BYTES, TAG_FINF);
5536 } while (0);
5537
5538 if (!NameInfo1 || !NameInfo2 || !FamInfo)
5539 {
5540 if (NameInfo2)
5541 ExFreePoolWithTag(NameInfo2, TAG_FINF);
5542
5543 if (NameInfo1)
5544 ExFreePoolWithTag(NameInfo1, TAG_FINF);
5545
5546 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5547 return FALSE;
5548 }
5549
5550 Count = 0;
5551
5552 /* Try to find the pathname in the global font list */
5553 IntLockGlobalFonts();
5554 for (ListEntry = g_FontListHead.Flink; ListEntry != &g_FontListHead;
5555 ListEntry = ListEntry->Flink)
5556 {
5557 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
5558 if (FontEntry->Font->Filename == NULL)
5559 continue;
5560
5561 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
5562 if (!IntGetFullFileName(NameInfo2, NAMEINFO_SIZE, &EntryFileName))
5563 continue;
5564
5565 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
5566 continue;
5567
5568 IsEqual = FALSE;
5569 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
5570 NULL, FontEntry->Font);
5571 for (i = 0; i < Count; ++i)
5572 {
5573 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
5574 {
5575 IsEqual = TRUE;
5576 break;
5577 }
5578 }
5579 if (!IsEqual)
5580 {
5581 /* Found */
5582 ++Count;
5583 if (Count >= MaxFamInfo)
5584 break;
5585 }
5586 }
5587 IntUnLockGlobalFonts();
5588
5589 /* Free the buffers */
5590 ExFreePoolWithTag(NameInfo1, TAG_FINF);
5591 ExFreePoolWithTag(NameInfo2, TAG_FINF);
5592
5593 if (Count == 0 && dwType != 5)
5594 {
5595 /* Font could not be found in system table
5596 dwType == 5 will still handle this */
5597 ExFreePoolWithTag(FamInfo, TAG_FINF);
5598 return FALSE;
5599 }
5600
5601 bSuccess = FALSE;
5602 switch (dwType)
5603 {
5604 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
5605 Size = sizeof(DWORD);
5606 if (*pdwBytes == 0)
5607 {
5608 *pdwBytes = Size;
5609 bSuccess = TRUE;
5610 }
5611 else if (pBuffer)
5612 {
5613 if (*pdwBytes >= Size)
5614 {
5615 *(DWORD*)pBuffer = Count;
5616 }
5617 *pdwBytes = Size;
5618 bSuccess = TRUE;
5619 }
5620 break;
5621
5622 case 1: /* copy the font title */
5623 /* calculate the required size */
5624 Size = 0;
5625 for (i = 0; i < Count; ++i)
5626 {
5627 if (i > 0)
5628 Size += 3; /* " & " */
5629 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
5630 if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
5631 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
5632 {
5633 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
5634 }
5635 }
5636 Size += 2; /* "\0\0" */
5637 Size *= sizeof(WCHAR);
5638
5639 if (*pdwBytes == 0)
5640 {
5641 *pdwBytes = Size;
5642 bSuccess = TRUE;
5643 }
5644 else if (pBuffer)
5645 {
5646 if (*pdwBytes >= Size)
5647 {
5648 /* store font title to buffer */
5649 WCHAR *psz = pBuffer;
5650 *psz = 0;
5651 for (i = 0; i < Count; ++i)
5652 {
5653 if (i > 0)
5654 wcscat(psz, L" & ");
5655 IntAddNameFromFamInfo(psz, &FamInfo[i]);
5656 }
5657 psz[wcslen(psz) + 1] = UNICODE_NULL;
5658 *pdwBytes = Size;
5659 bSuccess = TRUE;
5660 }
5661 else
5662 {
5663 *pdwBytes = 1024; /* this is confirmed value */
5664 }
5665 }
5666 break;
5667
5668 case 2: /* Copy an array of LOGFONTW */
5669 Size = Count * sizeof(LOGFONTW);
5670 if (*pdwBytes == 0)
5671 {
5672 *pdwBytes = Size;
5673 bSuccess = TRUE;
5674 }
5675 else if (pBuffer)
5676 {
5677 if (*pdwBytes >= Size)
5678 {
5679 pbBuffer = (LPBYTE)pBuffer;
5680 for (i = 0; i < Count; ++i)
5681 {
5682 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
5683 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
5684 pbBuffer += sizeof(LOGFONTW);
5685 }
5686 }
5687 *pdwBytes = Size;
5688 bSuccess = TRUE;
5689 }
5690 else
5691 {
5692 *pdwBytes = 1024; /* this is confirmed value */
5693 }
5694 break;
5695
5696 case 3:
5697 Size = sizeof(DWORD);
5698 if (*pdwBytes == 0)
5699 {
5700 *pdwBytes = Size;
5701 bSuccess = TRUE;
5702 }
5703 else if (pBuffer)
5704 {
5705 if (*pdwBytes >= Size)
5706 {
5707 /* FIXME: What exactly is copied here? */
5708 *(DWORD*)pBuffer = 1;
5709 }
5710 *pdwBytes = Size;
5711 bSuccess = TRUE;
5712 }
5713 break;
5714
5715 case 4: /* full file path */
5716 if (FileName->Length >= 4 * sizeof(WCHAR))
5717 {
5718 /* The beginning of FileName is \??\ */
5719 LPWSTR pch = FileName->Buffer + 4;
5720 DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
5721
5722 Size = Length + sizeof(WCHAR);
5723 if (*pdwBytes == 0)
5724 {
5725 *pdwBytes = Size;
5726 bSuccess = TRUE;
5727 }
5728 else if (pBuffer)
5729 {
5730 if (*pdwBytes >= Size)
5731 {
5732 RtlCopyMemory(pBuffer, pch, Size);
5733 }
5734 *pdwBytes = Size;
5735 bSuccess = TRUE;
5736 }
5737 }
5738 break;
5739
5740 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
5741 Size = sizeof(BOOL);
5742 if (*pdwBytes == 0)
5743 {
5744 *pdwBytes = Size;
5745 bSuccess = TRUE;
5746 }
5747 else if (pBuffer)
5748 {
5749 if (*pdwBytes >= Size)
5750 {
5751 *(BOOL*)pBuffer = Count == 0;
5752 }
5753 *pdwBytes = Size;
5754 bSuccess = TRUE;
5755 }
5756 break;
5757 }
5758 ExFreePoolWithTag(FamInfo, TAG_FINF);
5759
5760 return bSuccess;
5761 }
5762
5763
5764 BOOL
5765 FASTCALL
5766 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
5767 {
5768 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
5769 Info->iTechnology = RI_TECH_BITMAP;
5770 else
5771 {
5772 if (FT_IS_SCALABLE(Font->SharedFace->Face))
5773 Info->iTechnology = RI_TECH_SCALABLE;
5774 else
5775 Info->iTechnology = RI_TECH_FIXED;
5776 }
5777 Info->iUniq = Font->FontObj.iUniq;
5778 Info->dwUnknown = -1;
5779 return TRUE;
5780 }
5781
5782
5783 DWORD
5784 FASTCALL
5785 ftGdiGetKerningPairs( PFONTGDI Font,
5786 DWORD cPairs,
5787 LPKERNINGPAIR pKerningPair)
5788 {
5789 DWORD Count = 0;
5790 INT i = 0;
5791 FT_Face face = Font->SharedFace->Face;
5792
5793 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
5794 {
5795 FT_UInt previous_index = 0, glyph_index = 0;
5796 FT_ULong char_code, char_previous;
5797 FT_Vector delta;
5798
5799 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
5800
5801 IntLockFreeType();
5802
5803 while (glyph_index)
5804 {
5805 if (previous_index && glyph_index)
5806 {
5807 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
5808
5809 if (pKerningPair && cPairs)
5810 {
5811 pKerningPair[i].wFirst = char_previous;
5812 pKerningPair[i].wSecond = char_code;
5813 pKerningPair[i].iKernAmount = delta.x;
5814 i++;
5815 if (i == cPairs) break;
5816 }
5817 Count++;
5818 }
5819 previous_index = glyph_index;
5820 char_previous = char_code;
5821 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
5822 }
5823 IntUnLockFreeType();
5824 }
5825 return Count;
5826 }
5827
5828
5829 ///////////////////////////////////////////////////////////////////////////
5830 //
5831 // Functions needing sorting.
5832 //
5833 ///////////////////////////////////////////////////////////////////////////
5834
5835 LONG FASTCALL
5836 IntGetFontFamilyInfo(HDC Dc,
5837 const LOGFONTW *SafeLogFont,
5838 PFONTFAMILYINFO SafeInfo,
5839 LONG InfoCount)
5840 {
5841 LONG AvailCount = 0;
5842 PPROCESSINFO Win32Process;
5843
5844 /* Enumerate font families in the global list */
5845 IntLockGlobalFonts();
5846 if (!GetFontFamilyInfoForList(SafeLogFont, SafeInfo, NULL, &AvailCount,
5847 InfoCount, &g_FontListHead))
5848 {
5849 IntUnLockGlobalFonts();
5850 return -1;
5851 }
5852 IntUnLockGlobalFonts();
5853
5854 /* Enumerate font families in the process local list */
5855 Win32Process = PsGetCurrentProcessWin32Process();
5856 IntLockProcessPrivateFonts(Win32Process);
5857 if (!GetFontFamilyInfoForList(SafeLogFont, SafeInfo, NULL, &AvailCount, InfoCount,
5858 &Win32Process->PrivateFontListHead))
5859 {
5860 IntUnLockProcessPrivateFonts(Win32Process);
5861 return -1;
5862 }
5863 IntUnLockProcessPrivateFonts(Win32Process);
5864
5865 /* Enumerate font families in the registry */
5866 if (!GetFontFamilyInfoForSubstitutes(SafeLogFont, SafeInfo, &AvailCount, InfoCount))
5867 {
5868 return -1;
5869 }
5870
5871 return AvailCount;
5872 }
5873
5874 LONG NTAPI
5875 NtGdiGetFontFamilyInfo(HDC Dc,
5876 const LOGFONTW *UnsafeLogFont,
5877 PFONTFAMILYINFO UnsafeInfo,
5878 LPLONG UnsafeInfoCount)
5879 {
5880 NTSTATUS Status;
5881 LOGFONTW LogFont;
5882 PFONTFAMILYINFO Info;
5883 LONG GotCount, AvailCount, SafeInfoCount;
5884 ULONG DataSize;
5885
5886 if (UnsafeLogFont == NULL || UnsafeInfo == NULL || UnsafeInfoCount == NULL)
5887 {
5888 EngSetLastError(ERROR_INVALID_PARAMETER);
5889 return -1;
5890 }
5891
5892 Status = MmCopyFromCaller(&SafeInfoCount, UnsafeInfoCount, sizeof(SafeInfoCount));
5893 if (!NT_SUCCESS(Status))
5894 {
5895 EngSetLastError(ERROR_INVALID_PARAMETER);
5896 return -1;
5897 }
5898 GotCount = 0;
5899 Status = MmCopyToCaller(UnsafeInfoCount, &GotCount, sizeof(*UnsafeInfoCount));
5900 if (!NT_SUCCESS(Status))
5901 {
5902 EngSetLastError(ERROR_INVALID_PARAMETER);
5903 return -1;
5904 }
5905 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
5906 if (!NT_SUCCESS(Status))
5907 {
5908 EngSetLastError(ERROR_INVALID_PARAMETER);
5909 return -1;
5910 }
5911 if (SafeInfoCount <= 0)
5912 {
5913 EngSetLastError(ERROR_INVALID_PARAMETER);
5914 return -1;
5915 }
5916
5917 /* Allocate space for a safe copy */
5918 Status = RtlULongMult(SafeInfoCount, sizeof(FONTFAMILYINFO), &DataSize);
5919 if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
5920 {
5921 DPRINT1("Overflowed.\n");
5922 EngSetLastError(ERROR_INVALID_PARAMETER);
5923 return -1;
5924 }
5925 Info = ExAllocatePoolWithTag(PagedPool, DataSize, GDITAG_TEXT);
5926 if (Info == NULL)
5927 {
5928 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5929 return -1;
5930 }
5931
5932 /* Retrieve the information */
5933 AvailCount = IntGetFontFamilyInfo(Dc, &LogFont, Info, SafeInfoCount);
5934 GotCount = min(AvailCount, SafeInfoCount);
5935 SafeInfoCount = AvailCount;
5936
5937 /* Return data to caller */
5938 if (GotCount > 0)
5939 {
5940 Status = RtlULongMult(GotCount, sizeof(FONTFAMILYINFO), &DataSize);
5941 if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
5942 {
5943 DPRINT1("Overflowed.\n");
5944 ExFreePoolWithTag(Info, GDITAG_TEXT);
5945 EngSetLastError(ERROR_INVALID_PARAMETER);
5946 return -1;
5947 }
5948 Status = MmCopyToCaller(UnsafeInfo, Info, DataSize);
5949 if (!NT_SUCCESS(Status))
5950 {
5951 ExFreePoolWithTag(Info, GDITAG_TEXT);
5952 EngSetLastError(ERROR_INVALID_PARAMETER);
5953 return -1;
5954 }
5955 Status = MmCopyToCaller(UnsafeInfoCount, &SafeInfoCount, sizeof(*UnsafeInfoCount));
5956 if (!NT_SUCCESS(Status))
5957 {
5958 ExFreePoolWithTag(Info, GDITAG_TEXT);
5959 EngSetLastError(ERROR_INVALID_PARAMETER);
5960 return -1;
5961 }
5962 }
5963
5964 ExFreePoolWithTag(Info, GDITAG_TEXT);
5965
5966 return GotCount;
5967 }
5968
5969 FORCEINLINE
5970 LONG
5971 ScaleLong(LONG lValue, PFLOATOBJ pef)
5972 {
5973 FLOATOBJ efTemp;
5974
5975 /* Check if we have scaling different from 1 */
5976 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
5977 {
5978 /* Need to multiply */
5979 FLOATOBJ_SetLong(&efTemp, lValue);
5980 FLOATOBJ_Mul(&efTemp, pef);
5981 lValue = FLOATOBJ_GetLong(&efTemp);
5982 }
5983
5984 return lValue;
5985 }
5986
5987 BOOL
5988 APIENTRY
5989 IntExtTextOutW(
5990 IN PDC dc,
5991 IN INT XStart,
5992 IN INT YStart,
5993 IN UINT fuOptions,
5994 IN OPTIONAL PRECTL lprc,
5995 IN LPCWSTR String,
5996 IN INT Count,
5997 IN OPTIONAL LPINT Dx,
5998 IN DWORD dwCodePage)
5999 {
6000 /*
6001 * FIXME:
6002 * Call EngTextOut, which does the real work (calling DrvTextOut where
6003 * appropriate)
6004 */
6005
6006 PDC_ATTR pdcattr;
6007 SURFOBJ *SurfObj;
6008 SURFACE *psurf = NULL;
6009 int error, glyph_index, i;
6010 FT_Face face;
6011 FT_GlyphSlot glyph;
6012 FT_BitmapGlyph realglyph;
6013 LONGLONG TextLeft, RealXStart;
6014 ULONG TextTop, previous, BackgroundLeft;
6015 FT_Bool use_kerning;
6016 RECTL DestRect, MaskRect;
6017 POINTL SourcePoint, BrushOrigin;
6018 HBITMAP HSourceGlyph;
6019 SURFOBJ *SourceGlyphSurf;
6020 SIZEL bitSize;
6021 INT yoff;
6022 FONTOBJ *FontObj;
6023 PFONTGDI FontGDI;
6024 PTEXTOBJ TextObj = NULL;
6025 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
6026 FT_Render_Mode RenderMode;
6027 BOOLEAN Render;
6028 POINT Start;
6029 BOOL DoBreak = FALSE;
6030 USHORT DxShift;
6031 PMATRIX pmxWorldToDevice;
6032 LONG fixAscender, fixDescender;
6033 FLOATOBJ Scale;
6034 LOGFONTW *plf;
6035 BOOL EmuBold, EmuItalic;
6036 int thickness;
6037 BOOL bResult;
6038
6039 /* Check if String is valid */
6040 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
6041 {
6042 EngSetLastError(ERROR_INVALID_PARAMETER);
6043 return FALSE;
6044 }
6045
6046 Render = IntIsFontRenderingEnabled();
6047
6048 if (PATH_IsPathOpen(dc->dclevel))
6049 {
6050 bResult = PATH_ExtTextOut(dc,
6051 XStart,
6052 YStart,
6053 fuOptions,
6054 (const RECTL *)lprc,
6055 String,
6056 Count,
6057 (const INT *)Dx);
6058 return bResult;
6059 }
6060
6061 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
6062
6063 if (!dc->dclevel.pSurface)
6064 {
6065 /* Memory DC with no surface selected */
6066 bResult = TRUE;
6067 goto Cleanup;
6068 }
6069
6070 pdcattr = dc->pdcattr;
6071
6072 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
6073 {
6074 IntLPtoDP(dc, (POINT *)lprc, 2);
6075 }
6076
6077 if (pdcattr->flTextAlign & TA_UPDATECP)
6078 {
6079 Start.x = pdcattr->ptlCurrent.x;
6080 Start.y = pdcattr->ptlCurrent.y;
6081 } else {
6082 Start.x = XStart;
6083 Start.y = YStart;
6084 }
6085
6086 IntLPtoDP(dc, &Start, 1);
6087 RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
6088 YStart = Start.y + dc->ptlDCOrig.y;
6089
6090 SourcePoint.x = 0;
6091 SourcePoint.y = 0;
6092 MaskRect.left = 0;
6093 MaskRect.top = 0;
6094 BrushOrigin.x = 0;
6095 BrushOrigin.y = 0;
6096
6097 if ((fuOptions & ETO_OPAQUE) && lprc)
6098 {
6099 DestRect.left = lprc->left;
6100 DestRect.top = lprc->top;
6101 DestRect.right = lprc->right;
6102 DestRect.bottom = lprc->bottom;
6103
6104 DestRect.left += dc->ptlDCOrig.x;
6105 DestRect.top += dc->ptlDCOrig.y;
6106 DestRect.right += dc->ptlDCOrig.x;
6107 DestRect.bottom += dc->ptlDCOrig.y;
6108
6109 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
6110 {
6111 IntUpdateBoundsRect(dc, &DestRect);
6112 }
6113
6114 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
6115 DC_vUpdateBackgroundBrush(dc);
6116 if (dc->dctype == DCTYPE_DIRECT)
6117 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
6118
6119 psurf = dc->dclevel.pSurface;
6120 IntEngBitBlt(
6121 &psurf->SurfObj,
6122 NULL,
6123 NULL,
6124 (CLIPOBJ *)&dc->co,
6125 NULL,
6126 &DestRect,
6127 &SourcePoint,
6128 &SourcePoint,
6129 &dc->eboBackground.BrushObject,
6130 &BrushOrigin,
6131 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
6132
6133 if (dc->dctype == DCTYPE_DIRECT)
6134 MouseSafetyOnDrawEnd(dc->ppdev);
6135
6136 fuOptions &= ~ETO_OPAQUE;
6137 }
6138 else
6139 {
6140 if (pdcattr->jBkMode == OPAQUE)
6141 {
6142 fuOptions |= ETO_OPAQUE;
6143 }
6144 }
6145
6146 TextObj = RealizeFontInit(pdcattr->hlfntNew);
6147 if (TextObj == NULL)
6148 {
6149 bResult = FALSE;
6150 goto Cleanup;
6151 }
6152
6153 FontObj = TextObj->Font;
6154 ASSERT(FontObj);
6155 FontGDI = ObjToGDI(FontObj, FONT);
6156 ASSERT(FontGDI);
6157
6158 IntLockFreeType();
6159 face = FontGDI->SharedFace->Face;
6160
6161 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6162 EmuBold = EMUBOLD_NEEDED(FontGDI->OriginalWeight, plf->lfWeight);
6163 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
6164
6165 if (Render)
6166 RenderMode = IntGetFontRenderMode(plf);
6167 else
6168 RenderMode = FT_RENDER_MODE_MONO;
6169
6170 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
6171 {
6172 IntUnLockFreeType();
6173 bResult = FALSE;
6174 goto Cleanup;
6175 }
6176
6177 /* NOTE: Don't trust face->size->metrics.ascender and descender values. */
6178 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
6179 {
6180 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6181 FtSetCoordinateTransform(face, pmxWorldToDevice);
6182
6183 fixAscender = ScaleLong(FontGDI->tmAscent, &pmxWorldToDevice->efM22) << 6;
6184 fixDescender = ScaleLong(FontGDI->tmDescent, &pmxWorldToDevice->efM22) << 6;
6185 }
6186 else
6187 {
6188 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
6189 FtSetCoordinateTransform(face, pmxWorldToDevice);
6190
6191 fixAscender = FontGDI->tmAscent << 6;
6192 fixDescender = FontGDI->tmDescent << 6;
6193 }
6194
6195 /*
6196 * Process the vertical alignment and determine the yoff.
6197 */
6198 #define VALIGN_MASK (TA_TOP | TA_BASELINE | TA_BOTTOM)
6199 if ((pdcattr->flTextAlign & VALIGN_MASK) == TA_BASELINE)
6200 yoff = 0;
6201 else if ((pdcattr->flTextAlign & VALIGN_MASK) == TA_BOTTOM)
6202 yoff = -(fixDescender >> 6);
6203 else /* TA_TOP */
6204 yoff = fixAscender >> 6;
6205 #undef VALIGN_MASK
6206
6207 use_kerning = FT_HAS_KERNING(face);
6208 previous = 0;
6209
6210 /*
6211 * Process the horizontal alignment and modify XStart accordingly.
6212 */
6213 DxShift = fuOptions & ETO_PDY ? 1 : 0;
6214 if (pdcattr->flTextAlign & (TA_RIGHT | TA_CENTER))
6215 {
6216 ULONGLONG TextWidth = 0;
6217 LPCWSTR TempText = String;
6218 int iStart;
6219
6220 /*
6221 * Calculate width of the text.
6222 */
6223
6224 if (NULL != Dx)
6225 {
6226 iStart = Count < 2 ? 0 : Count - 2;
6227 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
6228 }
6229 else
6230 {
6231 iStart = 0;
6232 }
6233 TempText = String + iStart;
6234
6235 for (i = iStart; i < Count; i++)
6236 {
6237 glyph_index = get_glyph_index_flagged(face, *TempText, ETO_GLYPH_INDEX, fuOptions);
6238
6239 if (EmuBold || EmuItalic)
6240 realglyph = NULL;
6241 else
6242 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
6243 RenderMode, pmxWorldToDevice);
6244 if (!realglyph)
6245 {
6246 if (EmuItalic)
6247 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_BITMAP);
6248 else
6249 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6250 if (error)
6251 {
6252 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
6253 }
6254
6255 glyph = face->glyph;
6256 if (EmuBold || EmuItalic)
6257 {
6258 if (EmuBold)
6259 FT_GlyphSlot_Embolden(glyph);
6260 if (EmuItalic)
6261 FT_GlyphSlot_Oblique(glyph);
6262 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
6263 }
6264 else
6265 {
6266 realglyph = ftGdiGlyphCacheSet(face,
6267 glyph_index,
6268 plf->lfHeight,
6269 pmxWorldToDevice,
6270 glyph,
6271 RenderMode);
6272 }
6273 if (!realglyph)
6274 {
6275 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
6276 IntUnLockFreeType();
6277 goto Cleanup;
6278 }
6279
6280 }
6281 /* Retrieve kerning distance */
6282 if (use_kerning && previous && glyph_index)
6283 {
6284 FT_Vector delta;
6285 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
6286 TextWidth += delta.x;
6287 }
6288
6289 TextWidth += realglyph->root.advance.x >> 10;
6290
6291 if (EmuBold || EmuItalic)
6292 {
6293 FT_Done_Glyph((FT_Glyph)realglyph);
6294 realglyph = NULL;
6295 }
6296
6297 previous = glyph_index;
6298 TempText++;
6299 }
6300
6301 previous = 0;
6302
6303 if ((pdcattr->flTextAlign & TA_CENTER) == TA_CENTER)
6304 {
6305 RealXStart -= TextWidth / 2;
6306 }
6307 else
6308 {
6309 RealXStart -= TextWidth;
6310 }
6311 }
6312
6313 psurf = dc->dclevel.pSurface;
6314 SurfObj = &psurf->SurfObj ;
6315
6316 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
6317 DC_vUpdateBackgroundBrush(dc) ;
6318
6319 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
6320 DC_vUpdateTextBrush(dc) ;
6321
6322 if (!face->units_per_EM)
6323 {
6324 thickness = 1;
6325 }
6326 else
6327 {
6328 thickness = face->underline_thickness *
6329 face->size->metrics.y_ppem / face->units_per_EM;
6330 if (thickness <= 0)
6331 thickness = 1;
6332 }
6333
6334 if ((fuOptions & ETO_OPAQUE) && plf->lfItalic)
6335 {
6336 /* Draw background */
6337 TextLeft = RealXStart;
6338 TextTop = YStart;
6339 BackgroundLeft = (RealXStart + 32) >> 6;
6340 for (i = 0; i < Count; ++i)
6341 {
6342 glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions);
6343
6344 if (EmuItalic)
6345 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_BITMAP);
6346 else
6347 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6348 if (error)
6349 {
6350 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
6351 IntUnLockFreeType();
6352 goto Cleanup;
6353 }
6354
6355 glyph = face->glyph;
6356 if (EmuBold)
6357 FT_GlyphSlot_Embolden(glyph);
6358 if (EmuItalic)
6359 FT_GlyphSlot_Oblique(glyph);
6360 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
6361 if (!realglyph)
6362 {
6363 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
6364 IntUnLockFreeType();
6365 goto Cleanup;
6366 }
6367
6368 /* retrieve kerning distance and move pen position */
6369 if (use_kerning && previous && glyph_index && NULL == Dx)
6370 {
6371 FT_Vector delta;
6372 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
6373 TextLeft += delta.x;
6374 }
6375 DPRINT("TextLeft: %I64d\n", TextLeft);
6376 DPRINT("TextTop: %lu\n", TextTop);
6377 DPRINT("Advance: %d\n", realglyph->root.advance.x);
6378
6379 DestRect.left = BackgroundLeft;
6380 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
6381 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
6382 DestRect.bottom = DestRect.top + ((fixAscender + fixDescender) >> 6);
6383 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
6384 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
6385 {
6386 IntUpdateBoundsRect(dc, &DestRect);
6387 }
6388 IntEngBitBlt(
6389 &psurf->SurfObj,
6390 NULL,
6391 NULL,
6392 (CLIPOBJ *)&dc->co,
6393 NULL,
6394 &DestRect,
6395 &SourcePoint,
6396 &SourcePoint,
6397 &dc->eboBackground.BrushObject,
6398 &BrushOrigin,
6399 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
6400 MouseSafetyOnDrawEnd(dc->ppdev);
6401 BackgroundLeft = DestRect.right;
6402
6403 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
6404 DestRect.right = DestRect.left + realglyph->bitmap.width;
6405 DestRect.top = TextTop + yoff - realglyph->top;
6406 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
6407
6408 bitSize.cx = realglyph->bitmap.width;
6409 bitSize.cy = realglyph->bitmap.rows;
6410 MaskRect.right = realglyph->bitmap.width;
6411 MaskRect.bottom = realglyph->bitmap.rows;
6412
6413 if (NULL == Dx)
6414 {
6415 TextLeft += realglyph->root.advance.x >> 10;
6416 DPRINT("New TextLeft: %I64d\n", TextLeft);
6417 }
6418 else
6419 {
6420 // FIXME this should probably be a matrix transform with TextTop as well.
6421 Scale = pdcattr->mxWorldToDevice.efM11;
6422 if (FLOATOBJ_Equal0(&Scale))
6423 FLOATOBJ_Set1(&Scale);
6424
6425 /* do the shift before multiplying to preserve precision */
6426 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
6427 TextLeft += FLOATOBJ_GetLong(&Scale);
6428 DPRINT("New TextLeft2: %I64d\n", TextLeft);
6429 }
6430
6431 if (DxShift)
6432 {
6433 TextTop -= Dx[2 * i + 1] << 6;
6434 }
6435
6436 previous = glyph_index;
6437
6438 if (EmuBold || EmuItalic)
6439 {
6440 FT_Done_Glyph((FT_Glyph)realglyph);
6441 realglyph = NULL;
6442 }
6443 }
6444 }
6445
6446 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
6447 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
6448
6449 /* Assume success */
6450 bResult = TRUE;
6451
6452 /*
6453 * The main rendering loop.
6454 */
6455 TextLeft = RealXStart;
6456 TextTop = YStart;
6457 BackgroundLeft = (RealXStart + 32) >> 6;
6458 for (i = 0; i < Count; ++i)
6459 {
6460 glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions);
6461
6462 if (EmuBold || EmuItalic)
6463 realglyph = NULL;
6464 else
6465 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
6466 RenderMode, pmxWorldToDevice);
6467 if (!realglyph)
6468 {
6469 if (EmuItalic)
6470 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_BITMAP);
6471 else
6472 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6473 if (error)
6474 {
6475 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
6476 bResult = FALSE;
6477 break;
6478 }
6479
6480 glyph = face->glyph;
6481 if (EmuBold || EmuItalic)
6482 {
6483 if (EmuBold)
6484 FT_GlyphSlot_Embolden(glyph);
6485 if (EmuItalic)
6486 FT_GlyphSlot_Oblique(glyph);
6487 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
6488 }
6489 else
6490 {
6491 realglyph = ftGdiGlyphCacheSet(face,
6492 glyph_index,
6493 plf->lfHeight,
6494 pmxWorldToDevice,
6495 glyph,
6496 RenderMode);
6497 }
6498 if (!realglyph)
6499 {
6500 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
6501 bResult = FALSE;
6502 break;
6503 }
6504 }
6505
6506 /* retrieve kerning distance and move pen position */
6507 if (use_kerning && previous && glyph_index && NULL == Dx)
6508 {
6509 FT_Vector delta;
6510 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
6511 TextLeft += delta.x;
6512 }
6513 DPRINT("TextLeft: %I64d\n", TextLeft);
6514 DPRINT("TextTop: %lu\n", TextTop);
6515 DPRINT("Advance: %d\n", realglyph->root.advance.x);
6516
6517 if ((fuOptions & ETO_OPAQUE) && !plf->lfItalic)
6518 {
6519 DestRect.left = BackgroundLeft;
6520 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
6521 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
6522 DestRect.bottom = DestRect.top + ((fixAscender + fixDescender) >> 6);
6523
6524 if (dc->dctype == DCTYPE_DIRECT)
6525 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
6526
6527 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
6528 {
6529 IntUpdateBoundsRect(dc, &DestRect);
6530 }
6531 IntEngBitBlt(
6532 &psurf->SurfObj,
6533 NULL,
6534 NULL,
6535 (CLIPOBJ *)&dc->co,
6536 NULL,
6537 &DestRect,
6538 &SourcePoint,
6539 &SourcePoint,
6540 &dc->eboBackground.BrushObject,
6541 &BrushOrigin,
6542 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
6543
6544 if (dc->dctype == DCTYPE_DIRECT)
6545 MouseSafetyOnDrawEnd(dc->ppdev);
6546
6547 BackgroundLeft = DestRect.right;
6548 }
6549
6550 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
6551 DestRect.right = DestRect.left + realglyph->bitmap.width;
6552 DestRect.top = TextTop + yoff - realglyph->top;
6553 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
6554
6555 bitSize.cx = realglyph->bitmap.width;
6556 bitSize.cy = realglyph->bitmap.rows;
6557 MaskRect.right = realglyph->bitmap.width;
6558 MaskRect.bottom = realglyph->bitmap.rows;
6559
6560 /* Check if the bitmap has any pixels */
6561 if ((bitSize.cx != 0) && (bitSize.cy != 0))
6562 {
6563 /*
6564 * We should create the bitmap out of the loop at the biggest possible
6565 * glyph size. Then use memset with 0 to clear it and sourcerect to
6566 * limit the work of the transbitblt.
6567 */
6568 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
6569 BMF_8BPP, BMF_TOPDOWN,
6570 realglyph->bitmap.buffer);
6571 if ( !HSourceGlyph )
6572 {
6573 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
6574 // FT_Done_Glyph(realglyph);
6575 bResult = FALSE;
6576 break;
6577 }
6578 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
6579 if ( !SourceGlyphSurf )
6580 {
6581 EngDeleteSurface((HSURF)HSourceGlyph);
6582 DPRINT1("WARNING: EngLockSurface() failed!\n");
6583 bResult = FALSE;
6584 break;
6585 }
6586
6587 /*
6588 * Use the font data as a mask to paint onto the DCs surface using a
6589 * brush.
6590 */
6591 if (lprc && (fuOptions & ETO_CLIPPED) &&
6592 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
6593 {
6594 // We do the check '>=' instead of '>' to possibly save an iteration
6595 // through this loop, since it's breaking after the drawing is done,
6596 // and x is always incremented.
6597 DestRect.right = lprc->right + dc->ptlDCOrig.x;
6598 DoBreak = TRUE;
6599 }
6600 if (lprc && (fuOptions & ETO_CLIPPED) &&
6601 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
6602 {
6603 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
6604 }
6605
6606 if (dc->dctype == DCTYPE_DIRECT)
6607 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
6608
6609 if (!IntEngMaskBlt(
6610 SurfObj,
6611 SourceGlyphSurf,
6612 (CLIPOBJ *)&dc->co,
6613 &exloRGB2Dst.xlo,
6614 &exloDst2RGB.xlo,
6615 &DestRect,
6616 (PPOINTL)&MaskRect,
6617 &dc->eboText.BrushObject,
6618 &BrushOrigin))
6619 {
6620 DPRINT1("Failed to MaskBlt a glyph!\n");
6621 }
6622
6623 if (dc->dctype == DCTYPE_DIRECT)
6624 MouseSafetyOnDrawEnd(dc->ppdev) ;
6625
6626 EngUnlockSurface(SourceGlyphSurf);
6627 EngDeleteSurface((HSURF)HSourceGlyph);
6628 }
6629
6630 if (DoBreak)
6631 {
6632 break;
6633 }
6634
6635 if (plf->lfUnderline)
6636 {
6637 int i, position;
6638 if (!face->units_per_EM)
6639 {
6640 position = 0;
6641 }
6642 else
6643 {
6644 position = face->underline_position *
6645 face->size->metrics.y_ppem / face->units_per_EM;
6646 }
6647 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
6648 {
6649 EngLineTo(SurfObj,
6650 (CLIPOBJ *)&dc->co,
6651 &dc->eboText.BrushObject,
6652 (TextLeft >> 6),
6653 TextTop + yoff - position + i,
6654 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
6655 TextTop + yoff - position + i,
6656 NULL,
6657 ROP2_TO_MIX(R2_COPYPEN));
6658 }
6659 }
6660 if (plf->lfStrikeOut)
6661 {
6662 int i;
6663 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
6664 {
6665 EngLineTo(SurfObj,
6666 (CLIPOBJ *)&dc->co,
6667 &dc->eboText.BrushObject,
6668 (TextLeft >> 6),
6669 TextTop + yoff - (fixAscender >> 6) / 3 + i,
6670 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
6671 TextTop + yoff - (fixAscender >> 6) / 3 + i,
6672 NULL,
6673 ROP2_TO_MIX(R2_COPYPEN));
6674 }
6675 }
6676
6677 if (NULL == Dx)
6678 {
6679 TextLeft += realglyph->root.advance.x >> 10;
6680 DPRINT("New TextLeft: %I64d\n", TextLeft);
6681 }
6682 else
6683 {
6684 // FIXME this should probably be a matrix transform with TextTop as well.
6685 Scale = pdcattr->mxWorldToDevice.efM11;
6686 if (FLOATOBJ_Equal0(&Scale))
6687 FLOATOBJ_Set1(&Scale);
6688
6689 /* do the shift before multiplying to preserve precision */
6690 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
6691 TextLeft += FLOATOBJ_GetLong(&Scale);
6692 DPRINT("New TextLeft2: %I64d\n", TextLeft);
6693 }
6694
6695 if (DxShift)
6696 {
6697 TextTop -= Dx[2 * i + 1] << 6;
6698 }
6699
6700 previous = glyph_index;
6701
6702 if (EmuBold || EmuItalic)
6703 {
6704 FT_Done_Glyph((FT_Glyph)realglyph);
6705 realglyph = NULL;
6706 }
6707 }
6708
6709 if (pdcattr->flTextAlign & TA_UPDATECP) {
6710 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
6711 }
6712
6713 IntUnLockFreeType();
6714
6715 EXLATEOBJ_vCleanup(&exloRGB2Dst);
6716 EXLATEOBJ_vCleanup(&exloDst2RGB);
6717
6718 Cleanup:
6719
6720 DC_vFinishBlit(dc, NULL);
6721
6722 if (TextObj != NULL)
6723 TEXTOBJ_UnlockText(TextObj);
6724
6725 return bResult;
6726 }
6727
6728
6729 BOOL
6730 APIENTRY
6731 GreExtTextOutW(
6732 IN HDC hDC,
6733 IN INT XStart,
6734 IN INT YStart,
6735 IN UINT fuOptions,
6736 IN OPTIONAL PRECTL lprc,
6737 IN LPCWSTR String,
6738 IN INT Count,
6739 IN OPTIONAL LPINT Dx,
6740 IN DWORD dwCodePage)
6741 {
6742 BOOL bResult;
6743 DC *dc;
6744
6745 // TODO: Write test-cases to exactly match real Windows in different
6746 // bad parameters (e.g. does Windows check the DC or the RECT first?).
6747 dc = DC_LockDc(hDC);
6748 if (!dc)
6749 {
6750 EngSetLastError(ERROR_INVALID_HANDLE);
6751 return FALSE;
6752 }
6753
6754 bResult = IntExtTextOutW( dc,
6755 XStart,
6756 YStart,
6757 fuOptions,
6758 lprc,
6759 String,
6760 Count,
6761 Dx,
6762 dwCodePage );
6763
6764 DC_UnlockDc(dc);
6765
6766 return bResult;
6767 }
6768
6769 #define STACK_TEXT_BUFFER_SIZE 100
6770 BOOL
6771 APIENTRY
6772 NtGdiExtTextOutW(
6773 IN HDC hDC,
6774 IN INT XStart,
6775 IN INT YStart,
6776 IN UINT fuOptions,
6777 IN OPTIONAL LPRECT UnsafeRect,
6778 IN LPWSTR UnsafeString,
6779 IN INT Count,
6780 IN OPTIONAL LPINT UnsafeDx,
6781 IN DWORD dwCodePage)
6782 {
6783 BOOL Result = FALSE;
6784 NTSTATUS Status = STATUS_SUCCESS;
6785 RECTL SafeRect;
6786 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
6787 PVOID Buffer = LocalBuffer;
6788 LPCWSTR SafeString = NULL;
6789 LPINT SafeDx = NULL;
6790 ULONG BufSize, StringSize, DxSize = 0;
6791
6792 /* Check if String is valid */
6793 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
6794 {
6795 EngSetLastError(ERROR_INVALID_PARAMETER);
6796 return FALSE;
6797 }
6798
6799 if (Count > 0)
6800 {
6801 /* Calculate buffer size for string and Dx values */
6802 BufSize = StringSize = Count * sizeof(WCHAR);
6803 if (UnsafeDx)
6804 {
6805 /* If ETO_PDY is specified, we have pairs of INTs */
6806 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
6807 BufSize += DxSize;
6808 }
6809
6810 /* Check if our local buffer is large enough */
6811 if (BufSize > STACK_TEXT_BUFFER_SIZE)
6812 {
6813 /* It's not, allocate a temp buffer */
6814 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
6815 if (!Buffer)
6816 {
6817 return FALSE;
6818 }
6819 }
6820
6821 /* Probe and copy user mode data to the buffer */
6822 _SEH2_TRY
6823 {
6824 /* Put the Dx before the String to assure alignment of 4 */
6825 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
6826
6827 /* Probe and copy the string */
6828 ProbeForRead(UnsafeString, StringSize, 1);
6829 RtlCopyMemory((PVOID)SafeString, UnsafeString, StringSize);
6830
6831 /* If we have Dx values... */
6832 if (UnsafeDx)
6833 {
6834 /* ... probe and copy them */
6835 SafeDx = Buffer;
6836 ProbeForRead(UnsafeDx, DxSize, 1);
6837 RtlCopyMemory(SafeDx, UnsafeDx, DxSize);
6838 }
6839 }
6840 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6841 {
6842 Status = _SEH2_GetExceptionCode();
6843 }
6844 _SEH2_END
6845 if (!NT_SUCCESS(Status))
6846 {
6847 goto cleanup;
6848 }
6849 }
6850
6851 /* If we have a rect, copy it */
6852 if (UnsafeRect)
6853 {
6854 _SEH2_TRY
6855 {
6856 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
6857 SafeRect = *UnsafeRect;
6858 }
6859 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6860 {
6861 Status = _SEH2_GetExceptionCode();
6862 }
6863 _SEH2_END
6864 if (!NT_SUCCESS(Status))
6865 {
6866 goto cleanup;
6867 }
6868 }
6869
6870 /* Finally call the internal routine */
6871 Result = GreExtTextOutW(hDC,
6872 XStart,
6873 YStart,
6874 fuOptions,
6875 &SafeRect,
6876 SafeString,
6877 Count,
6878 SafeDx,
6879 dwCodePage);
6880
6881 cleanup:
6882 /* If we allocated a buffer, free it */
6883 if (Buffer != LocalBuffer)
6884 {
6885 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6886 }
6887
6888 return Result;
6889 }
6890
6891
6892 /*
6893 * @implemented
6894 */
6895 BOOL
6896 APIENTRY
6897 NtGdiGetCharABCWidthsW(
6898 IN HDC hDC,
6899 IN UINT FirstChar,
6900 IN ULONG Count,
6901 IN OPTIONAL PWCHAR UnSafepwch,
6902 IN FLONG fl,
6903 OUT PVOID Buffer)
6904 {
6905 LPABC SafeBuff;
6906 LPABCFLOAT SafeBuffF = NULL;
6907 PDC dc;
6908 PDC_ATTR pdcattr;
6909 PTEXTOBJ TextObj;
6910 PFONTGDI FontGDI;
6911 FT_Face face;
6912 FT_CharMap charmap, found = NULL;
6913 UINT i, glyph_index, BufferSize;
6914 HFONT hFont = 0;
6915 NTSTATUS Status = STATUS_SUCCESS;
6916 PMATRIX pmxWorldToDevice;
6917 PWCHAR Safepwch = NULL;
6918 LOGFONTW *plf;
6919
6920 if (!Buffer)
6921 {
6922 EngSetLastError(ERROR_INVALID_PARAMETER);
6923 return FALSE;
6924 }
6925
6926 if (UnSafepwch)
6927 {
6928 UINT pwchSize = Count * sizeof(WCHAR);
6929 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
6930
6931 if(!Safepwch)
6932 {
6933 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6934 return FALSE;
6935 }
6936
6937 _SEH2_TRY
6938 {
6939 ProbeForRead(UnSafepwch, pwchSize, 1);
6940 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
6941 }
6942 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6943 {
6944 Status = _SEH2_GetExceptionCode();
6945 }
6946 _SEH2_END;
6947 }
6948
6949 if (!NT_SUCCESS(Status))
6950 {
6951 if(Safepwch)
6952 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6953
6954 EngSetLastError(Status);
6955 return FALSE;
6956 }
6957
6958 BufferSize = Count * sizeof(ABC); // Same size!
6959 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6960 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
6961 if (SafeBuff == NULL)
6962 {
6963
6964 if(Safepwch)
6965 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6966
6967 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6968 return FALSE;
6969 }
6970
6971 dc = DC_LockDc(hDC);
6972 if (dc == NULL)
6973 {
6974 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6975
6976 if(Safepwch)
6977 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6978
6979 EngSetLastError(ERROR_INVALID_HANDLE);
6980 return FALSE;
6981 }
6982 pdcattr = dc->pdcattr;
6983 hFont = pdcattr->hlfntNew;
6984 TextObj = RealizeFontInit(hFont);
6985
6986 /* Get the DC's world-to-device transformation matrix */
6987 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6988 DC_UnlockDc(dc);
6989
6990 if (TextObj == NULL)
6991 {
6992 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6993
6994 if(Safepwch)
6995 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6996
6997 EngSetLastError(ERROR_INVALID_HANDLE);
6998 return FALSE;
6999 }
7000
7001 FontGDI = ObjToGDI(TextObj->Font, FONT);
7002
7003 face = FontGDI->SharedFace->Face;
7004 if (face->charmap == NULL)
7005 {
7006 for (i = 0; i < (UINT)face->num_charmaps; i++)
7007 {
7008 charmap = face->charmaps[i];
7009 if (charmap->encoding != 0)
7010 {
7011 found = charmap;
7012 break;
7013 }
7014 }
7015
7016 if (!found)
7017 {
7018 DPRINT1("WARNING: Could not find desired charmap!\n");
7019 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7020
7021 if(Safepwch)
7022 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7023
7024 EngSetLastError(ERROR_INVALID_HANDLE);
7025 return FALSE;
7026 }
7027
7028 IntLockFreeType();
7029 FT_Set_Charmap(face, found);
7030 IntUnLockFreeType();
7031 }
7032
7033 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
7034 IntLockFreeType();
7035 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
7036 FtSetCoordinateTransform(face, pmxWorldToDevice);
7037
7038 for (i = FirstChar; i < FirstChar+Count; i++)
7039 {
7040 int adv, lsb, bbx, left, right;
7041
7042 if (Safepwch)
7043 {
7044 glyph_index = get_glyph_index_flagged(face, Safepwch[i - FirstChar], GCABCW_INDICES, fl);
7045 }
7046 else
7047 {
7048 glyph_index = get_glyph_index_flagged(face, i, GCABCW_INDICES, fl);
7049 }
7050 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
7051
7052 left = (INT)face->glyph->metrics.horiBearingX & -64;
7053 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
7054 adv = (face->glyph->advance.x + 32) >> 6;
7055
7056 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
7057 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
7058
7059 lsb = left >> 6;
7060 bbx = (right - left) >> 6;
7061 /*
7062 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
7063 */
7064 if (!fl)
7065 {
7066 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
7067 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
7068 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
7069 }
7070 else
7071 {
7072 SafeBuff[i - FirstChar].abcA = lsb;
7073 SafeBuff[i - FirstChar].abcB = bbx;
7074 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
7075 }
7076 }
7077 IntUnLockFreeType();
7078 TEXTOBJ_UnlockText(TextObj);
7079 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
7080
7081 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7082
7083 if(Safepwch)
7084 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7085
7086 if (!NT_SUCCESS(Status))
7087 {
7088 SetLastNtError(Status);
7089 return FALSE;
7090 }
7091
7092 DPRINT("NtGdiGetCharABCWidths Worked!\n");
7093 return TRUE;
7094 }
7095
7096 /*
7097 * @implemented
7098 */
7099 BOOL
7100 APIENTRY
7101 NtGdiGetCharWidthW(
7102 IN HDC hDC,
7103 IN UINT FirstChar,
7104 IN UINT Count,
7105 IN OPTIONAL PWCHAR UnSafepwc,
7106 IN FLONG fl,
7107 OUT PVOID Buffer)
7108 {
7109 NTSTATUS Status = STATUS_SUCCESS;
7110 LPINT SafeBuff;
7111 PFLOAT SafeBuffF = NULL;
7112 PDC dc;
7113 PDC_ATTR pdcattr;
7114 PTEXTOBJ TextObj;
7115 PFONTGDI FontGDI;
7116 FT_Face face;
7117 FT_CharMap charmap, found = NULL;
7118 UINT i, glyph_index, BufferSize;
7119 HFONT hFont = 0;
7120 PMATRIX pmxWorldToDevice;
7121 PWCHAR Safepwc = NULL;
7122 LOGFONTW *plf;
7123
7124 if (UnSafepwc)
7125 {
7126 UINT pwcSize = Count * sizeof(WCHAR);
7127 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
7128
7129 if(!Safepwc)
7130 {
7131 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
7132 return FALSE;
7133 }
7134 _SEH2_TRY
7135 {
7136 ProbeForRead(UnSafepwc, pwcSize, 1);
7137 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
7138 }
7139 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7140 {
7141 Status = _SEH2_GetExceptionCode();
7142 }
7143 _SEH2_END;
7144 }
7145
7146 if (!NT_SUCCESS(Status))
7147 {
7148 EngSetLastError(Status);
7149 return FALSE;
7150 }
7151
7152 BufferSize = Count * sizeof(INT); // Same size!
7153 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
7154 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
7155 if (SafeBuff == NULL)
7156 {
7157 if(Safepwc)
7158 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7159
7160 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
7161 return FALSE;
7162 }
7163
7164 dc = DC_LockDc(hDC);
7165 if (dc == NULL)
7166 {
7167 if(Safepwc)
7168 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7169
7170 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7171 EngSetLastError(ERROR_INVALID_HANDLE);
7172 return FALSE;
7173 }
7174 pdcattr = dc->pdcattr;
7175 hFont = pdcattr->hlfntNew;
7176 TextObj = RealizeFontInit(hFont);
7177 /* Get the DC's world-to-device transformation matrix */
7178 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
7179 DC_UnlockDc(dc);
7180
7181 if (TextObj == NULL)
7182 {
7183 if(Safepwc)
7184 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7185
7186 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7187 EngSetLastError(ERROR_INVALID_HANDLE);
7188 return FALSE;
7189 }
7190
7191 FontGDI = ObjToGDI(TextObj->Font, FONT);
7192
7193 face = FontGDI->SharedFace->Face;
7194 if (face->charmap == NULL)
7195 {
7196 for (i = 0; i < (UINT)face->num_charmaps; i++)
7197 {
7198 charmap = face->charmaps[i];
7199 if (charmap->encoding != 0)
7200 {
7201 found = charmap;
7202 break;
7203 }
7204 }
7205
7206 if (!found)
7207 {
7208 DPRINT1("WARNING: Could not find desired charmap!\n");
7209
7210 if(Safepwc)
7211 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7212
7213 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7214 EngSetLastError(ERROR_INVALID_HANDLE);
7215 return FALSE;
7216 }
7217
7218 IntLockFreeType();
7219 FT_Set_Charmap(face, found);
7220 IntUnLockFreeType();
7221 }
7222
7223 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
7224 IntLockFreeType();
7225 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
7226 FtSetCoordinateTransform(face, pmxWorldToDevice);
7227
7228 for (i = FirstChar; i < FirstChar+Count; i++)
7229 {
7230 if (Safepwc)
7231 {
7232 glyph_index = get_glyph_index_flagged(face, Safepwc[i - FirstChar], GCW_INDICES, fl);
7233 }
7234 else
7235 {
7236 glyph_index = get_glyph_index_flagged(face, i, GCW_INDICES, fl);
7237 }
7238 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
7239 if (!fl)
7240 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
7241 else
7242 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
7243 }
7244 IntUnLockFreeType();
7245 TEXTOBJ_UnlockText(TextObj);
7246 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
7247
7248 if(Safepwc)
7249 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7250
7251 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7252 return TRUE;
7253 }
7254
7255
7256 /*
7257 * @implemented
7258 */
7259 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
7260 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
7261 // NOTE: See also GreGetGlyphIndicesW.
7262 __kernel_entry
7263 W32KAPI
7264 DWORD
7265 APIENTRY
7266 NtGdiGetGlyphIndicesW(
7267 _In_ HDC hdc,
7268 _In_reads_opt_(cwc) LPCWSTR pwc,
7269 _In_ INT cwc,
7270 _Out_writes_opt_(cwc) LPWORD pgi,
7271 _In_ DWORD iMode)
7272 {
7273 PDC dc;
7274 PDC_ATTR pdcattr;
7275 PTEXTOBJ TextObj;
7276 PFONTGDI FontGDI;
7277 HFONT hFont = NULL;
7278 NTSTATUS Status = STATUS_SUCCESS;
7279 OUTLINETEXTMETRICW *potm;
7280 INT i;
7281 WCHAR DefChar = 0xffff;
7282 PWSTR Buffer = NULL;
7283 ULONG Size, pwcSize;
7284 PWSTR Safepwc = NULL;
7285 LPCWSTR UnSafepwc = pwc;
7286 LPWORD UnSafepgi = pgi;
7287 FT_Face Face;
7288 TT_OS2 *pOS2;
7289
7290 if (cwc < 0)
7291 {
7292 DPRINT1("cwc < 0\n");
7293 return GDI_ERROR;
7294 }
7295
7296 if (!UnSafepwc && !UnSafepgi && cwc > 0)
7297 {
7298 DPRINT1("!UnSafepwc && !UnSafepgi && cwc > 0\n");
7299 return GDI_ERROR;
7300 }
7301
7302 if (!UnSafepwc != !UnSafepgi)
7303 {
7304 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
7305 return GDI_ERROR;
7306 }
7307
7308 /* Get FontGDI */
7309 dc = DC_LockDc(hdc);
7310 if (!dc)
7311 {
7312 DPRINT1("!DC_LockDC\n");
7313 return GDI_ERROR;
7314 }
7315 pdcattr = dc->pdcattr;
7316 hFont = pdcattr->hlfntNew;
7317 TextObj = RealizeFontInit(hFont);
7318 DC_UnlockDc(dc);
7319 if (!TextObj)
7320 {
7321 DPRINT1("!TextObj\n");
7322 return GDI_ERROR;
7323 }
7324 FontGDI = ObjToGDI(TextObj->Font, FONT);
7325 TEXTOBJ_UnlockText(TextObj);
7326
7327 if (cwc == 0)
7328 {
7329 if (!UnSafepwc && !UnSafepgi)
7330 {
7331 Face = FontGDI->SharedFace->Face;
7332 return Face->num_glyphs;
7333 }
7334 else
7335 {
7336 Status = STATUS_UNSUCCESSFUL;
7337 goto ErrorRet;
7338 }
7339 }
7340
7341 Buffer = ExAllocatePoolWithTag(PagedPool, cwc * sizeof(WORD), GDITAG_TEXT);
7342 if (!Buffer)
7343 {
7344 DPRINT1("ExAllocatePoolWithTag\n");
7345 return GDI_ERROR;
7346 }
7347
7348 /* Get DefChar */
7349 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
7350 {
7351 DefChar = 0xffff;
7352 }
7353 else
7354 {
7355 Face = FontGDI->SharedFace->Face;
7356 if (FT_IS_SFNT(Face))
7357 {
7358 IntLockFreeType();
7359 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
7360 DefChar = (pOS2->usDefaultChar ? get_glyph_index(Face, pOS2->usDefaultChar) : 0);
7361 IntUnLockFreeType();
7362 }
7363 else
7364 {
7365 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
7366 if (!Size)
7367 {
7368 Status = STATUS_UNSUCCESSFUL;
7369 DPRINT1("!Size\n");
7370 goto ErrorRet;
7371 }
7372 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
7373 if (!potm)
7374 {
7375 Status = STATUS_INSUFFICIENT_RESOURCES;
7376 DPRINT1("!potm\n");
7377 goto ErrorRet;
7378 }
7379 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
7380 if (Size)
7381 DefChar = potm->otmTextMetrics.tmDefaultChar;
7382 ExFreePoolWithTag(potm, GDITAG_TEXT);
7383 }
7384 }
7385
7386 /* Allocate for Safepwc */
7387 pwcSize = cwc * sizeof(WCHAR);
7388 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
7389 if (!Safepwc)
7390 {
7391 Status = STATUS_NO_MEMORY;
7392 DPRINT1("!Safepwc\n");
7393 goto ErrorRet;
7394 }
7395
7396 _SEH2_TRY
7397 {
7398 ProbeForRead(UnSafepwc, pwcSize, 1);
7399 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
7400 }
7401 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7402 {
7403 Status = _SEH2_GetExceptionCode();
7404 }
7405 _SEH2_END;
7406
7407 if (!NT_SUCCESS(Status))
7408 {
7409 DPRINT1("Status: %08lX\n", Status);
7410 goto ErrorRet;
7411 }
7412
7413 /* Get glyph indeces */
7414 IntLockFreeType();
7415 for (i = 0; i < cwc; i++)
7416 {
7417 Buffer[i] = get_glyph_index(FontGDI->SharedFace->Face, Safepwc[i]);
7418 if (Buffer[i] == 0)
7419 {
7420 Buffer[i] = DefChar;
7421 }
7422 }
7423 IntUnLockFreeType();
7424
7425 _SEH2_TRY
7426 {
7427 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
7428 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
7429 }
7430 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7431 {
7432 Status = _SEH2_GetExceptionCode();
7433 }
7434 _SEH2_END;
7435
7436 ErrorRet:
7437 if (Buffer != NULL)
7438 {
7439 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
7440 }
7441 if (Safepwc != NULL)
7442 {
7443 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7444 }
7445
7446 if (NT_SUCCESS(Status))
7447 return cwc;
7448
7449 return GDI_ERROR;
7450 }
7451
7452 /* EOF */