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