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