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