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