[FONT][WIN32SS] Do not return an uninitialized variable
[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 IntLockFreeType();
4146 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4147 IntUnLockFreeType();
4148 memset(&fs, 0, sizeof(FONTSIGNATURE));
4149 if (NULL != pOS2)
4150 {
4151 fs.fsCsb[0] = pOS2->ulCodePageRange1;
4152 fs.fsCsb[1] = pOS2->ulCodePageRange2;
4153 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
4154 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
4155 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
4156 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
4157 if (pOS2->version == 0)
4158 {
4159 FT_UInt dummy;
4160
4161 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
4162 fs.fsCsb[0] |= FS_LATIN1;
4163 else
4164 fs.fsCsb[0] |= FS_SYMBOL;
4165 }
4166 }
4167 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
4168 if (fs.fsCsb[0] == 0)
4169 { /* Let's see if we can find any interesting cmaps */
4170 for (i = 0; i < Face->num_charmaps; i++)
4171 {
4172 switch (Face->charmaps[i]->encoding)
4173 {
4174 case FT_ENCODING_UNICODE:
4175 case FT_ENCODING_APPLE_ROMAN:
4176 fs.fsCsb[0] |= FS_LATIN1;
4177 break;
4178 case FT_ENCODING_MS_SYMBOL:
4179 fs.fsCsb[0] |= FS_SYMBOL;
4180 break;
4181 default:
4182 break;
4183 }
4184 }
4185 }
4186 if (lpSig)
4187 {
4188 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
4189 }
4190
4191 RtlGetDefaultCodePage(&usACP, &usOEM);
4192 cp = usACP;
4193
4194 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
4195 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
4196 {
4197 DPRINT("Hit 1\n");
4198 Ret = csi.ciCharset;
4199 goto Exit;
4200 }
4201
4202 for (i = 0; i < MAXTCIINDEX; i++)
4203 {
4204 fs0 = 1L << i;
4205 if (fs.fsCsb[0] & fs0)
4206 {
4207 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
4208 {
4209 // *cp = csi.ciACP;
4210 DPRINT("Hit 2\n");
4211 Ret = csi.ciCharset;
4212 goto Exit;
4213 }
4214 else
4215 DPRINT1("TCI failing on %x\n", fs0);
4216 }
4217 }
4218 Exit:
4219 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
4220 return (MAKELONG(csi.ciACP, csi.ciCharset));
4221 }
4222
4223
4224 DWORD
4225 FASTCALL
4226 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
4227 {
4228 DWORD size = 0;
4229 DWORD num_ranges = 0;
4230 FT_Face face = Font->SharedFace->Face;
4231
4232 if (face->charmap->encoding == FT_ENCODING_UNICODE)
4233 {
4234 FT_UInt glyph_code = 0;
4235 FT_ULong char_code, char_code_prev;
4236
4237 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
4238
4239 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4240 face->num_glyphs, glyph_code, char_code);
4241
4242 if (!glyph_code) return 0;
4243
4244 if (glyphset)
4245 {
4246 glyphset->ranges[0].wcLow = (USHORT)char_code;
4247 glyphset->ranges[0].cGlyphs = 0;
4248 glyphset->cGlyphsSupported = 0;
4249 }
4250
4251 num_ranges = 1;
4252 while (glyph_code)
4253 {
4254 if (char_code < char_code_prev)
4255 {
4256 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
4257 return 0;
4258 }
4259 if (char_code - char_code_prev > 1)
4260 {
4261 num_ranges++;
4262 if (glyphset)
4263 {
4264 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4265 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
4266 glyphset->cGlyphsSupported++;
4267 }
4268 }
4269 else if (glyphset)
4270 {
4271 glyphset->ranges[num_ranges - 1].cGlyphs++;
4272 glyphset->cGlyphsSupported++;
4273 }
4274 char_code_prev = char_code;
4275 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
4276 }
4277 }
4278 else
4279 DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
4280
4281 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4282 if (glyphset)
4283 {
4284 glyphset->cbThis = size;
4285 glyphset->cRanges = num_ranges;
4286 glyphset->flAccel = 0;
4287 }
4288 return size;
4289 }
4290
4291
4292 BOOL
4293 FASTCALL
4294 ftGdiGetTextMetricsW(
4295 HDC hDC,
4296 PTMW_INTERNAL ptmwi)
4297 {
4298 PDC dc;
4299 PDC_ATTR pdcattr;
4300 PTEXTOBJ TextObj;
4301 PFONTGDI FontGDI;
4302 FT_Face Face;
4303 TT_OS2 *pOS2;
4304 TT_HoriHeader *pHori;
4305 FT_WinFNT_HeaderRec Win;
4306 ULONG Error;
4307 NTSTATUS Status = STATUS_SUCCESS;
4308 LOGFONTW *plf;
4309
4310 if (!ptmwi)
4311 {
4312 EngSetLastError(STATUS_INVALID_PARAMETER);
4313 return FALSE;
4314 }
4315
4316 if (!(dc = DC_LockDc(hDC)))
4317 {
4318 EngSetLastError(ERROR_INVALID_HANDLE);
4319 return FALSE;
4320 }
4321 pdcattr = dc->pdcattr;
4322 TextObj = RealizeFontInit(pdcattr->hlfntNew);
4323 if (NULL != TextObj)
4324 {
4325 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4326 FontGDI = ObjToGDI(TextObj->Font, FONT);
4327
4328 Face = FontGDI->SharedFace->Face;
4329
4330 IntLockFreeType();
4331 Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
4332 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
4333 IntUnLockFreeType();
4334
4335 if (0 != Error)
4336 {
4337 DPRINT1("Error in setting pixel sizes: %u\n", Error);
4338 Status = STATUS_UNSUCCESSFUL;
4339 }
4340 else
4341 {
4342 FT_Face Face = FontGDI->SharedFace->Face;
4343 Status = STATUS_SUCCESS;
4344
4345 IntLockFreeType();
4346 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4347 if (NULL == pOS2)
4348 {
4349 DPRINT1("Can't find OS/2 table - not TT font?\n");
4350 Status = STATUS_INTERNAL_ERROR;
4351 }
4352
4353 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
4354 if (NULL == pHori)
4355 {
4356 DPRINT1("Can't find HHEA table - not TT font?\n");
4357 Status = STATUS_INTERNAL_ERROR;
4358 }
4359
4360 Error = FT_Get_WinFNT_Header(Face, &Win);
4361
4362 if (NT_SUCCESS(Status))
4363 {
4364 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
4365
4366 /* FIXME: Fill Diff member */
4367 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
4368 }
4369
4370 IntUnLockFreeType();
4371 }
4372 TEXTOBJ_UnlockText(TextObj);
4373 }
4374 else
4375 {
4376 Status = STATUS_INVALID_HANDLE;
4377 }
4378 DC_UnlockDc(dc);
4379
4380 if (!NT_SUCCESS(Status))
4381 {
4382 SetLastNtError(Status);
4383 return FALSE;
4384 }
4385 return TRUE;
4386 }
4387
4388 DWORD
4389 FASTCALL
4390 ftGdiGetFontData(
4391 PFONTGDI FontGdi,
4392 DWORD Table,
4393 DWORD Offset,
4394 PVOID Buffer,
4395 DWORD Size)
4396 {
4397 DWORD Result = GDI_ERROR;
4398 FT_Face Face = FontGdi->SharedFace->Face;
4399
4400 IntLockFreeType();
4401
4402 if (FT_IS_SFNT(Face))
4403 {
4404 if (Table)
4405 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
4406 (Table << 8 & 0xFF0000);
4407
4408 if (!Buffer) Size = 0;
4409
4410 if (Buffer && Size)
4411 {
4412 FT_Error Error;
4413 FT_ULong Needed = 0;
4414
4415 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
4416
4417 if ( !Error && Needed < Size) Size = Needed;
4418 }
4419 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
4420 Result = Size;
4421 }
4422
4423 IntUnLockFreeType();
4424
4425 return Result;
4426 }
4427
4428 #define GOT_PENALTY(name, value) Penalty += (value)
4429
4430 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
4431 static UINT
4432 GetFontPenalty(const LOGFONTW * LogFont,
4433 const OUTLINETEXTMETRICW * Otm,
4434 const char * style_name)
4435 {
4436 ULONG Penalty = 0;
4437 BYTE Byte;
4438 LONG Long;
4439 BOOL fNeedScaling = FALSE;
4440 const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
4441 const TEXTMETRICW * TM = &Otm->otmTextMetrics;
4442 WCHAR* ActualNameW;
4443
4444 ASSERT(Otm);
4445 ASSERT(LogFont);
4446
4447 /* FIXME: IntSizeSynth Penalty 20 */
4448 /* FIXME: SmallPenalty Penalty 1 */
4449 /* FIXME: FaceNameSubst Penalty 500 */
4450
4451 Byte = LogFont->lfCharSet;
4452 if (Byte == DEFAULT_CHARSET)
4453 {
4454 if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0)
4455 {
4456 if (Byte == ANSI_CHARSET)
4457 {
4458 DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
4459 }
4460 /* We assume SYMBOL_CHARSET for "Marlett" font */
4461 Byte = SYMBOL_CHARSET;
4462 }
4463 }
4464
4465 if (Byte != TM->tmCharSet)
4466 {
4467 if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
4468 {
4469 /* CharSet Penalty 65000 */
4470 /* Requested charset does not match the candidate's. */
4471 GOT_PENALTY("CharSet", 65000);
4472 }
4473 else
4474 {
4475 if (UserCharSet != TM->tmCharSet)
4476 {
4477 /* UNDOCUMENTED: Not user language */
4478 GOT_PENALTY("UNDOCUMENTED:NotUserLanguage", 100);
4479
4480 if (ANSI_CHARSET != TM->tmCharSet)
4481 {
4482 /* UNDOCUMENTED: Not ANSI charset */
4483 GOT_PENALTY("UNDOCUMENTED:NotAnsiCharSet", 100);
4484 }
4485 }
4486 }
4487 }
4488
4489 Byte = LogFont->lfOutPrecision;
4490 switch (Byte)
4491 {
4492 case OUT_DEFAULT_PRECIS:
4493 /* nothing to do */
4494 break;
4495 case OUT_DEVICE_PRECIS:
4496 if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
4497 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
4498 {
4499 /* OutputPrecision Penalty 19000 */
4500 /* Requested OUT_STROKE_PRECIS, but the device can't do it
4501 or the candidate is not a vector font. */
4502 GOT_PENALTY("OutputPrecision", 19000);
4503 }
4504 break;
4505 default:
4506 if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
4507 {
4508 /* OutputPrecision Penalty 19000 */
4509 /* Or OUT_STROKE_PRECIS not requested, and the candidate
4510 is a vector font that requires GDI support. */
4511 GOT_PENALTY("OutputPrecision", 19000);
4512 }
4513 break;
4514 }
4515
4516 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4517 if (Byte == DEFAULT_PITCH)
4518 Byte = VARIABLE_PITCH;
4519 if (Byte == FIXED_PITCH)
4520 {
4521 if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
4522 {
4523 /* FixedPitch Penalty 15000 */
4524 /* Requested a fixed pitch font, but the candidate is a
4525 variable pitch font. */
4526 GOT_PENALTY("FixedPitch", 15000);
4527 }
4528 }
4529 if (Byte == VARIABLE_PITCH)
4530 {
4531 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4532 {
4533 /* PitchVariable Penalty 350 */
4534 /* Requested a variable pitch font, but the candidate is not a
4535 variable pitch font. */
4536 GOT_PENALTY("PitchVariable", 350);
4537 }
4538 }
4539
4540 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4541 if (Byte == DEFAULT_PITCH)
4542 {
4543 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4544 {
4545 /* DefaultPitchFixed Penalty 1 */
4546 /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
4547 GOT_PENALTY("DefaultPitchFixed", 1);
4548 }
4549 }
4550
4551 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
4552
4553 if (LogFont->lfFaceName[0])
4554 {
4555 BOOL Found = FALSE;
4556
4557 /* localized family name */
4558 if (!Found)
4559 {
4560 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4561 }
4562 /* localized full name */
4563 if (!Found)
4564 {
4565 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
4566 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4567 }
4568 if (!Found)
4569 {
4570 /* FaceName Penalty 10000 */
4571 /* Requested a face name, but the candidate's face name
4572 does not match. */
4573 GOT_PENALTY("FaceName", 10000);
4574 }
4575 }
4576
4577 Byte = (LogFont->lfPitchAndFamily & 0xF0);
4578 if (Byte != FF_DONTCARE)
4579 {
4580 if (Byte != (TM->tmPitchAndFamily & 0xF0))
4581 {
4582 /* Family Penalty 9000 */
4583 /* Requested a family, but the candidate's family is different. */
4584 GOT_PENALTY("Family", 9000);
4585 }
4586 }
4587
4588 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
4589 {
4590 /* FamilyUnknown Penalty 8000 */
4591 /* Requested a family, but the candidate has no family. */
4592 GOT_PENALTY("FamilyUnknown", 8000);
4593 }
4594
4595 /* Is the candidate a non-vector font? */
4596 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4597 {
4598 /* Is lfHeight specified? */
4599 if (LogFont->lfHeight != 0)
4600 {
4601 if (labs(LogFont->lfHeight) < TM->tmHeight)
4602 {
4603 /* HeightBigger Penalty 600 */
4604 /* The candidate is a nonvector font and is bigger than the
4605 requested height. */
4606 GOT_PENALTY("HeightBigger", 600);
4607 /* HeightBiggerDifference Penalty 150 */
4608 /* The candidate is a raster font and is larger than the
4609 requested height. Penalty * height difference */
4610 GOT_PENALTY("HeightBiggerDifference", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)));
4611
4612 fNeedScaling = TRUE;
4613 }
4614 if (TM->tmHeight < labs(LogFont->lfHeight))
4615 {
4616 /* HeightSmaller Penalty 150 */
4617 /* The candidate is a raster font and is smaller than the
4618 requested height. Penalty * height difference */
4619 GOT_PENALTY("HeightSmaller", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)));
4620
4621 fNeedScaling = TRUE;
4622 }
4623 }
4624 }
4625
4626 switch (LogFont->lfPitchAndFamily & 0xF0)
4627 {
4628 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4629 switch (TM->tmPitchAndFamily & 0xF0)
4630 {
4631 case FF_DECORATIVE: case FF_SCRIPT:
4632 /* FamilyUnlikely Penalty 50 */
4633 /* Requested a roman/modern/swiss family, but the
4634 candidate is decorative/script. */
4635 GOT_PENALTY("FamilyUnlikely", 50);
4636 break;
4637 default:
4638 break;
4639 }
4640 break;
4641 case FF_DECORATIVE: case FF_SCRIPT:
4642 switch (TM->tmPitchAndFamily & 0xF0)
4643 {
4644 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4645 /* FamilyUnlikely Penalty 50 */
4646 /* Or requested decorative/script, and the candidate is
4647 roman/modern/swiss. */
4648 GOT_PENALTY("FamilyUnlikely", 50);
4649 break;
4650 default:
4651 break;
4652 }
4653 default:
4654 break;
4655 }
4656
4657 if (LogFont->lfWidth != 0)
4658 {
4659 if (LogFont->lfWidth != TM->tmAveCharWidth)
4660 {
4661 /* Width Penalty 50 */
4662 /* Requested a nonzero width, but the candidate's width
4663 doesn't match. Penalty * width difference */
4664 GOT_PENALTY("Width", 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth));
4665
4666 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4667 fNeedScaling = TRUE;
4668 }
4669 }
4670
4671 if (fNeedScaling)
4672 {
4673 /* SizeSynth Penalty 50 */
4674 /* The candidate is a raster font that needs scaling by GDI. */
4675 GOT_PENALTY("SizeSynth", 50);
4676 }
4677
4678 if (!!LogFont->lfItalic != !!TM->tmItalic)
4679 {
4680 if (!LogFont->lfItalic && ItalicFromStyle(style_name))
4681 {
4682 /* Italic Penalty 4 */
4683 /* Requested font and candidate font do not agree on italic status,
4684 and the desired result cannot be simulated. */
4685 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
4686 GOT_PENALTY("Italic", 40);
4687 }
4688 else if (LogFont->lfItalic && !ItalicFromStyle(style_name))
4689 {
4690 /* ItalicSim Penalty 1 */
4691 /* Requested italic font but the candidate is not italic,
4692 although italics can be simulated. */
4693 GOT_PENALTY("ItalicSim", 1);
4694 }
4695 }
4696
4697 if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
4698 {
4699 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
4700 {
4701 /* NotTrueType Penalty 4 */
4702 /* Requested OUT_TT_PRECIS, but the candidate is not a
4703 TrueType font. */
4704 GOT_PENALTY("NotTrueType", 4);
4705 }
4706 }
4707
4708 Long = LogFont->lfWeight;
4709 if (LogFont->lfWeight == FW_DONTCARE)
4710 Long = FW_NORMAL;
4711 if (Long != TM->tmWeight)
4712 {
4713 /* Weight Penalty 3 */
4714 /* The candidate's weight does not match the requested weight.
4715 Penalty * (weight difference/10) */
4716 GOT_PENALTY("Weight", 3 * (labs(Long - TM->tmWeight) / 10));
4717 }
4718
4719 if (!LogFont->lfUnderline && TM->tmUnderlined)
4720 {
4721 /* Underline Penalty 3 */
4722 /* Requested font has no underline, but the candidate is
4723 underlined. */
4724 GOT_PENALTY("Underline", 3);
4725 }
4726
4727 if (!LogFont->lfStrikeOut && TM->tmStruckOut)
4728 {
4729 /* StrikeOut Penalty 3 */
4730 /* Requested font has no strike-out, but the candidate is
4731 struck out. */
4732 GOT_PENALTY("StrikeOut", 3);
4733 }
4734
4735 /* Is the candidate a non-vector font? */
4736 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4737 {
4738 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
4739 {
4740 /* VectorHeightSmaller Penalty 2 */
4741 /* Candidate is a vector font that is smaller than the
4742 requested height. Penalty * height difference */
4743 GOT_PENALTY("VectorHeightSmaller", 2 * labs(TM->tmHeight - LogFont->lfHeight));
4744 }
4745 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
4746 {
4747 /* VectorHeightBigger Penalty 1 */
4748 /* Candidate is a vector font that is bigger than the
4749 requested height. Penalty * height difference */
4750 GOT_PENALTY("VectorHeightBigger", 1 * labs(TM->tmHeight - LogFont->lfHeight));
4751 }
4752 }
4753
4754 if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
4755 {
4756 /* DeviceFavor Penalty 2 */
4757 /* Extra penalty for all nondevice fonts. */
4758 GOT_PENALTY("DeviceFavor", 2);
4759 }
4760
4761 if (TM->tmAveCharWidth >= 5 && TM->tmHeight >= 5)
4762 {
4763 if (TM->tmAveCharWidth / TM->tmHeight >= 3)
4764 {
4765 /* Aspect Penalty 30 */
4766 /* The aspect rate is >= 3. It seems like a bad font. */
4767 GOT_PENALTY("Aspect", ((TM->tmAveCharWidth / TM->tmHeight) - 2) * 30);
4768 }
4769 else if (TM->tmHeight / TM->tmAveCharWidth >= 3)
4770 {
4771 /* Aspect Penalty 30 */
4772 /* The aspect rate is >= 3. It seems like a bad font. */
4773 GOT_PENALTY("Aspect", ((TM->tmHeight / TM->tmAveCharWidth) - 2) * 30);
4774 }
4775 }
4776
4777 if (Penalty < 200)
4778 {
4779 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
4780 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
4781 "tmCharSet:%d, tmWeight:%ld\n",
4782 Penalty, LogFont->lfFaceName, ActualNameW,
4783 LogFont->lfCharSet, LogFont->lfWeight,
4784 TM->tmCharSet, TM->tmWeight);
4785 }
4786
4787 return Penalty; /* success */
4788 }
4789
4790 #undef GOT_PENALTY
4791
4792 static __inline VOID
4793 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
4794 const LOGFONTW *LogFont,
4795 const PLIST_ENTRY Head)
4796 {
4797 ULONG Penalty;
4798 PLIST_ENTRY Entry;
4799 PFONT_ENTRY CurrentEntry;
4800 FONTGDI *FontGDI;
4801 OUTLINETEXTMETRICW *Otm = NULL;
4802 UINT OtmSize, OldOtmSize = 0;
4803 FT_Face Face;
4804
4805 ASSERT(FontObj);
4806 ASSERT(MatchPenalty);
4807 ASSERT(LogFont);
4808 ASSERT(Head);
4809
4810 /* Start with a pretty big buffer */
4811 OldOtmSize = 0x200;
4812 Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
4813
4814 /* get the FontObj of lowest penalty */
4815 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
4816 {
4817 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
4818
4819 FontGDI = CurrentEntry->Font;
4820 ASSERT(FontGDI);
4821 Face = FontGDI->SharedFace->Face;
4822
4823 /* get text metrics */
4824 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4825 if (OtmSize > OldOtmSize)
4826 {
4827 if (Otm)
4828 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4829 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
4830 }
4831
4832 /* update FontObj if lowest penalty */
4833 if (Otm)
4834 {
4835 IntLockFreeType();
4836 IntRequestFontSize(NULL, FontGDI, LogFont->lfWidth, LogFont->lfHeight);
4837 IntUnLockFreeType();
4838
4839 OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
4840 if (!OtmSize)
4841 continue;
4842
4843 OldOtmSize = OtmSize;
4844
4845 Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
4846 if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
4847 {
4848 *FontObj = GDIToObj(FontGDI, FONT);
4849 *MatchPenalty = Penalty;
4850 }
4851 }
4852 }
4853
4854 if (Otm)
4855 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4856 }
4857
4858 static
4859 VOID
4860 FASTCALL
4861 IntFontType(PFONTGDI Font)
4862 {
4863 PS_FontInfoRec psfInfo;
4864 FT_ULong tmp_size = 0;
4865 FT_Face Face = Font->SharedFace->Face;
4866
4867 if (FT_HAS_MULTIPLE_MASTERS(Face))
4868 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
4869 if (FT_HAS_VERTICAL(Face))
4870 Font->FontObj.flFontType |= FO_VERT_FACE;
4871 if (!FT_IS_SCALABLE(Face))
4872 Font->FontObj.flFontType |= FO_TYPE_RASTER;
4873 if (FT_IS_SFNT(Face))
4874 {
4875 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
4876 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
4877 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4878 }
4879 if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
4880 {
4881 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4882 }
4883 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
4884 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
4885 {
4886 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
4887 }
4888 }
4889
4890 static BOOL
4891 MatchFontName(PSHARED_FACE SharedFace, LPCWSTR lfFaceName, FT_UShort NameID, FT_UShort LangID)
4892 {
4893 NTSTATUS Status;
4894 UNICODE_STRING Name1, Name2;
4895
4896 if (lfFaceName[0] == UNICODE_NULL)
4897 return FALSE;
4898
4899 RtlInitUnicodeString(&Name1, lfFaceName);
4900
4901 RtlInitUnicodeString(&Name2, NULL);
4902 Status = IntGetFontLocalizedName(&Name2, SharedFace, NameID, LangID);
4903
4904 if (NT_SUCCESS(Status))
4905 {
4906 if (RtlCompareUnicodeString(&Name1, &Name2, TRUE) == 0)
4907 {
4908 RtlFreeUnicodeString(&Name2);
4909 return TRUE;
4910 }
4911
4912 RtlFreeUnicodeString(&Name2);
4913 }
4914
4915 return FALSE;
4916 }
4917
4918 static BOOL
4919 MatchFontNames(PSHARED_FACE SharedFace, LPCWSTR lfFaceName)
4920 {
4921 if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, LANG_ENGLISH) ||
4922 MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, LANG_ENGLISH))
4923 {
4924 return TRUE;
4925 }
4926 if (PRIMARYLANGID(gusLanguageID) != LANG_ENGLISH)
4927 {
4928 if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, gusLanguageID) ||
4929 MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, gusLanguageID))
4930 {
4931 return TRUE;
4932 }
4933 }
4934 return FALSE;
4935 }
4936
4937 NTSTATUS
4938 FASTCALL
4939 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
4940 {
4941 NTSTATUS Status = STATUS_SUCCESS;
4942 PTEXTOBJ TextObj;
4943 PPROCESSINFO Win32Process;
4944 ULONG MatchPenalty;
4945 LOGFONTW *pLogFont;
4946 LOGFONTW SubstitutedLogFont;
4947 FT_Face Face;
4948
4949 if (!pTextObj)
4950 {
4951 TextObj = TEXTOBJ_LockText(FontHandle);
4952 if (NULL == TextObj)
4953 {
4954 return STATUS_INVALID_HANDLE;
4955 }
4956
4957 if (TextObj->fl & TEXTOBJECT_INIT)
4958 {
4959 TEXTOBJ_UnlockText(TextObj);
4960 return STATUS_SUCCESS;
4961 }
4962 }
4963 else
4964 {
4965 TextObj = pTextObj;
4966 }
4967
4968 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4969
4970 /* substitute */
4971 SubstitutedLogFont = *pLogFont;
4972 DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
4973 SubstituteFontRecurse(&SubstitutedLogFont);
4974 DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
4975
4976 MatchPenalty = 0xFFFFFFFF;
4977 TextObj->Font = NULL;
4978
4979 Win32Process = PsGetCurrentProcessWin32Process();
4980
4981 /* Search private fonts */
4982 IntLockProcessPrivateFonts(Win32Process);
4983 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4984 &Win32Process->PrivateFontListHead);
4985 IntUnLockProcessPrivateFonts(Win32Process);
4986
4987 /* Search system fonts */
4988 IntLockGlobalFonts();
4989 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4990 &g_FontListHead);
4991 IntUnLockGlobalFonts();
4992
4993 if (NULL == TextObj->Font)
4994 {
4995 DPRINT1("Request font %S not found, no fonts loaded at all\n",
4996 pLogFont->lfFaceName);
4997 Status = STATUS_NOT_FOUND;
4998 }
4999 else
5000 {
5001 UNICODE_STRING Name;
5002 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
5003 PSHARED_FACE SharedFace = FontGdi->SharedFace;
5004
5005 IntLockFreeType();
5006 IntRequestFontSize(NULL, FontGdi, pLogFont->lfWidth, pLogFont->lfHeight);
5007 IntUnLockFreeType();
5008
5009 TextObj->TextFace[0] = UNICODE_NULL;
5010 if (MatchFontNames(SharedFace, SubstitutedLogFont.lfFaceName))
5011 {
5012 RtlStringCchCopyW(TextObj->TextFace, _countof(TextObj->TextFace), pLogFont->lfFaceName);
5013 }
5014 else
5015 {
5016 RtlInitUnicodeString(&Name, NULL);
5017 Status = IntGetFontLocalizedName(&Name, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
5018 if (NT_SUCCESS(Status))
5019 {
5020 /* truncated copy */
5021 IntUnicodeStringToBuffer(TextObj->TextFace, sizeof(TextObj->TextFace), &Name);
5022 RtlFreeUnicodeString(&Name);
5023 }
5024 }
5025
5026 // Need hdev, when freetype is loaded need to create DEVOBJ for
5027 // Consumer and Producer.
5028 TextObj->Font->iUniq = 1; // Now it can be cached.
5029 IntFontType(FontGdi);
5030 FontGdi->flType = TextObj->Font->flFontType;
5031 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
5032 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
5033 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
5034 if (pLogFont->lfWeight != FW_DONTCARE)
5035 FontGdi->RequestWeight = pLogFont->lfWeight;
5036 else
5037 FontGdi->RequestWeight = FW_NORMAL;
5038
5039 Face = FontGdi->SharedFace->Face;
5040
5041 //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name);
5042
5043 if (!FontGdi->OriginalItalic)
5044 FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name);
5045
5046 TextObj->fl |= TEXTOBJECT_INIT;
5047 Status = STATUS_SUCCESS;
5048 }
5049
5050 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
5051
5052 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
5053
5054 return Status;
5055 }
5056
5057
5058 static
5059 BOOL
5060 FASTCALL
5061 IntGetFullFileName(
5062 POBJECT_NAME_INFORMATION NameInfo,
5063 ULONG Size,
5064 PUNICODE_STRING FileName)
5065 {
5066 NTSTATUS Status;
5067 OBJECT_ATTRIBUTES ObjectAttributes;
5068 HANDLE hFile;
5069 IO_STATUS_BLOCK IoStatusBlock;
5070 ULONG Desired;
5071
5072 InitializeObjectAttributes(&ObjectAttributes,
5073 FileName,
5074 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
5075 NULL,
5076 NULL);
5077
5078 Status = ZwOpenFile(
5079 &hFile,
5080 0, // FILE_READ_ATTRIBUTES,
5081 &ObjectAttributes,
5082 &IoStatusBlock,
5083 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5084 0);
5085
5086 if (!NT_SUCCESS(Status))
5087 {
5088 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
5089 return FALSE;
5090 }
5091
5092 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
5093 ZwClose(hFile);
5094 if (!NT_SUCCESS(Status))
5095 {
5096 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
5097 return FALSE;
5098 }
5099
5100 return TRUE;
5101 }
5102
5103 static BOOL
5104 EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2)
5105 {
5106 const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
5107 const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
5108 const LOGFONTW *plf1 = &pLog1->elfLogFont;
5109 const LOGFONTW *plf2 = &pLog2->elfLogFont;
5110
5111 if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0)
5112 {
5113 return FALSE;
5114 }
5115
5116 if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0)
5117 {
5118 return FALSE;
5119 }
5120
5121 return TRUE;
5122 }
5123
5124 static VOID
5125 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
5126 {
5127 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
5128 if (FamInfo->EnumLogFontEx.elfStyle[0] &&
5129 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
5130 {
5131 wcscat(psz, L" ");
5132 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
5133 }
5134 }
5135
5136 BOOL
5137 FASTCALL
5138 IntGdiGetFontResourceInfo(
5139 PUNICODE_STRING FileName,
5140 PVOID pBuffer,
5141 DWORD *pdwBytes,
5142 DWORD dwType)
5143 {
5144 UNICODE_STRING EntryFileName;
5145 POBJECT_NAME_INFORMATION NameInfo1 = NULL, NameInfo2 = NULL;
5146 PLIST_ENTRY ListEntry;
5147 PFONT_ENTRY FontEntry;
5148 ULONG Size, i, Count;
5149 LPBYTE pbBuffer;
5150 BOOL IsEqual;
5151 FONTFAMILYINFO *FamInfo;
5152 const ULONG MaxFamInfo = 64;
5153 const ULONG MAX_FAM_INFO_BYTES = sizeof(FONTFAMILYINFO) * MaxFamInfo;
5154 BOOL bSuccess;
5155 const ULONG NAMEINFO_SIZE = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
5156
5157 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
5158
5159 do
5160 {
5161 /* Create buffer for full path name */
5162 NameInfo1 = ExAllocatePoolWithTag(PagedPool, NAMEINFO_SIZE, TAG_FINF);
5163 if (!NameInfo1)
5164 break;
5165
5166 /* Get the full path name */
5167 if (!IntGetFullFileName(NameInfo1, NAMEINFO_SIZE, FileName))
5168 break;
5169
5170 /* Create a buffer for the entries' names */
5171 NameInfo2 = ExAllocatePoolWithTag(PagedPool, NAMEINFO_SIZE, TAG_FINF);
5172 if (!NameInfo2)
5173 break;
5174
5175 FamInfo = ExAllocatePoolWithTag(PagedPool, MAX_FAM_INFO_BYTES, TAG_FINF);
5176 } while (0);
5177
5178 if (!NameInfo1 || !NameInfo2 || !FamInfo)
5179 {
5180 if (NameInfo2)
5181 ExFreePoolWithTag(NameInfo2, TAG_FINF);
5182
5183 if (NameInfo1)
5184 ExFreePoolWithTag(NameInfo1, TAG_FINF);
5185
5186 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5187 return FALSE;
5188 }
5189
5190 Count = 0;
5191
5192 /* Try to find the pathname in the global font list */
5193 IntLockGlobalFonts();
5194 for (ListEntry = g_FontListHead.Flink; ListEntry != &g_FontListHead;
5195 ListEntry = ListEntry->Flink)
5196 {
5197 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
5198 if (FontEntry->Font->Filename == NULL)
5199 continue;
5200
5201 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
5202 if (!IntGetFullFileName(NameInfo2, NAMEINFO_SIZE, &EntryFileName))
5203 continue;
5204
5205 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
5206 continue;
5207
5208 IsEqual = FALSE;
5209 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
5210 NULL, FontEntry->Font);
5211 for (i = 0; i < Count; ++i)
5212 {
5213 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
5214 {
5215 IsEqual = TRUE;
5216 break;
5217 }
5218 }
5219 if (!IsEqual)
5220 {
5221 /* Found */
5222 ++Count;
5223 if (Count >= MaxFamInfo)
5224 break;
5225 }
5226 }
5227 IntUnLockGlobalFonts();
5228
5229 /* Free the buffers */
5230 ExFreePoolWithTag(NameInfo1, TAG_FINF);
5231 ExFreePoolWithTag(NameInfo2, TAG_FINF);
5232
5233 if (Count == 0 && dwType != 5)
5234 {
5235 /* Font could not be found in system table
5236 dwType == 5 will still handle this */
5237 ExFreePoolWithTag(FamInfo, TAG_FINF);
5238 return FALSE;
5239 }
5240
5241 bSuccess = FALSE;
5242 switch (dwType)
5243 {
5244 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
5245 Size = sizeof(DWORD);
5246 if (*pdwBytes == 0)
5247 {
5248 *pdwBytes = Size;
5249 bSuccess = TRUE;
5250 }
5251 else if (pBuffer)
5252 {
5253 if (*pdwBytes >= Size)
5254 {
5255 *(DWORD*)pBuffer = Count;
5256 }
5257 *pdwBytes = Size;
5258 bSuccess = TRUE;
5259 }
5260 break;
5261
5262 case 1: /* copy the font title */
5263 /* calculate the required size */
5264 Size = 0;
5265 for (i = 0; i < Count; ++i)
5266 {
5267 if (i > 0)
5268 Size += 3; /* " & " */
5269 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
5270 if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
5271 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
5272 {
5273 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
5274 }
5275 }
5276 Size += 2; /* "\0\0" */
5277 Size *= sizeof(WCHAR);
5278
5279 if (*pdwBytes == 0)
5280 {
5281 *pdwBytes = Size;
5282 bSuccess = TRUE;
5283 }
5284 else if (pBuffer)
5285 {
5286 if (*pdwBytes >= Size)
5287 {
5288 /* store font title to buffer */
5289 WCHAR *psz = pBuffer;
5290 *psz = 0;
5291 for (i = 0; i < Count; ++i)
5292 {
5293 if (i > 0)
5294 wcscat(psz, L" & ");
5295 IntAddNameFromFamInfo(psz, &FamInfo[i]);
5296 }
5297 psz[wcslen(psz) + 1] = UNICODE_NULL;
5298 *pdwBytes = Size;
5299 bSuccess = TRUE;
5300 }
5301 else
5302 {
5303 *pdwBytes = 1024; /* this is confirmed value */
5304 }
5305 }
5306 break;
5307
5308 case 2: /* Copy an array of LOGFONTW */
5309 Size = Count * sizeof(LOGFONTW);
5310 if (*pdwBytes == 0)
5311 {
5312 *pdwBytes = Size;
5313 bSuccess = TRUE;
5314 }
5315 else if (pBuffer)
5316 {
5317 if (*pdwBytes >= Size)
5318 {
5319 pbBuffer = (LPBYTE)pBuffer;
5320 for (i = 0; i < Count; ++i)
5321 {
5322 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
5323 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
5324 pbBuffer += sizeof(LOGFONTW);
5325 }
5326 }
5327 *pdwBytes = Size;
5328 bSuccess = TRUE;
5329 }
5330 else
5331 {
5332 *pdwBytes = 1024; /* this is confirmed value */
5333 }
5334 break;
5335
5336 case 3:
5337 Size = sizeof(DWORD);
5338 if (*pdwBytes == 0)
5339 {
5340 *pdwBytes = Size;
5341 bSuccess = TRUE;
5342 }
5343 else if (pBuffer)
5344 {
5345 if (*pdwBytes >= Size)
5346 {
5347 /* FIXME: What exactly is copied here? */
5348 *(DWORD*)pBuffer = 1;
5349 }
5350 *pdwBytes = Size;
5351 bSuccess = TRUE;
5352 }
5353 break;
5354
5355 case 4: /* full file path */
5356 if (FileName->Length >= 4 * sizeof(WCHAR))
5357 {
5358 /* The beginning of FileName is \??\ */
5359 LPWSTR pch = FileName->Buffer + 4;
5360 DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
5361
5362 Size = Length + sizeof(WCHAR);
5363 if (*pdwBytes == 0)
5364 {
5365 *pdwBytes = Size;
5366 bSuccess = TRUE;
5367 }
5368 else if (pBuffer)
5369 {
5370 if (*pdwBytes >= Size)
5371 {
5372 RtlCopyMemory(pBuffer, pch, Size);
5373 }
5374 *pdwBytes = Size;
5375 bSuccess = TRUE;
5376 }
5377 }
5378 break;
5379
5380 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
5381 Size = sizeof(BOOL);
5382 if (*pdwBytes == 0)
5383 {
5384 *pdwBytes = Size;
5385 bSuccess = TRUE;
5386 }
5387 else if (pBuffer)
5388 {
5389 if (*pdwBytes >= Size)
5390 {
5391 *(BOOL*)pBuffer = Count == 0;
5392 }
5393 *pdwBytes = Size;
5394 bSuccess = TRUE;
5395 }
5396 break;
5397 }
5398 ExFreePoolWithTag(FamInfo, TAG_FINF);
5399
5400 return bSuccess;
5401 }
5402
5403
5404 BOOL
5405 FASTCALL
5406 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
5407 {
5408 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
5409 Info->iTechnology = RI_TECH_BITMAP;
5410 else
5411 {
5412 if (FT_IS_SCALABLE(Font->SharedFace->Face))
5413 Info->iTechnology = RI_TECH_SCALABLE;
5414 else
5415 Info->iTechnology = RI_TECH_FIXED;
5416 }
5417 Info->iUniq = Font->FontObj.iUniq;
5418 Info->dwUnknown = -1;
5419 return TRUE;
5420 }
5421
5422
5423 DWORD
5424 FASTCALL
5425 ftGdiGetKerningPairs( PFONTGDI Font,
5426 DWORD cPairs,
5427 LPKERNINGPAIR pKerningPair)
5428 {
5429 DWORD Count = 0;
5430 INT i = 0;
5431 FT_Face face = Font->SharedFace->Face;
5432
5433 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
5434 {
5435 FT_UInt previous_index = 0, glyph_index = 0;
5436 FT_ULong char_code, char_previous;
5437 FT_Vector delta;
5438
5439 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
5440
5441 IntLockFreeType();
5442
5443 while (glyph_index)
5444 {
5445 if (previous_index && glyph_index)
5446 {
5447 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
5448
5449 if (pKerningPair && cPairs)
5450 {
5451 pKerningPair[i].wFirst = char_previous;
5452 pKerningPair[i].wSecond = char_code;
5453 pKerningPair[i].iKernAmount = delta.x;
5454 i++;
5455 if (i == cPairs) break;
5456 }
5457 Count++;
5458 }
5459 previous_index = glyph_index;
5460 char_previous = char_code;
5461 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
5462 }
5463 IntUnLockFreeType();
5464 }
5465 return Count;
5466 }
5467
5468
5469 ///////////////////////////////////////////////////////////////////////////
5470 //
5471 // Functions needing sorting.
5472 //
5473 ///////////////////////////////////////////////////////////////////////////
5474 int APIENTRY
5475 NtGdiGetFontFamilyInfo(HDC Dc,
5476 LPLOGFONTW UnsafeLogFont,
5477 PFONTFAMILYINFO UnsafeInfo,
5478 DWORD Size)
5479 {
5480 NTSTATUS Status;
5481 LOGFONTW LogFont;
5482 PFONTFAMILYINFO Info;
5483 DWORD Count;
5484 PPROCESSINFO Win32Process;
5485
5486 /* Make a safe copy */
5487 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
5488 if (! NT_SUCCESS(Status))
5489 {
5490 EngSetLastError(ERROR_INVALID_PARAMETER);
5491 return -1;
5492 }
5493
5494 /* Allocate space for a safe copy */
5495 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT);
5496 if (NULL == Info)
5497 {
5498 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5499 return -1;
5500 }
5501
5502 /* Enumerate font families in the global list */
5503 IntLockGlobalFonts();
5504 Count = 0;
5505 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &g_FontListHead) )
5506 {
5507 IntUnLockGlobalFonts();
5508 ExFreePoolWithTag(Info, GDITAG_TEXT);
5509 return -1;
5510 }
5511 IntUnLockGlobalFonts();
5512
5513 /* Enumerate font families in the process local list */
5514 Win32Process = PsGetCurrentProcessWin32Process();
5515 IntLockProcessPrivateFonts(Win32Process);
5516 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
5517 &Win32Process->PrivateFontListHead))
5518 {
5519 IntUnLockProcessPrivateFonts(Win32Process);
5520 ExFreePoolWithTag(Info, GDITAG_TEXT);
5521 return -1;
5522 }
5523 IntUnLockProcessPrivateFonts(Win32Process);
5524
5525 /* Enumerate font families in the registry */
5526 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
5527 {
5528 ExFreePoolWithTag(Info, GDITAG_TEXT);
5529 return -1;
5530 }
5531
5532 /* Return data to caller */
5533 if (0 != Count)
5534 {
5535 Status = MmCopyToCaller(UnsafeInfo, Info,
5536 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
5537 if (! NT_SUCCESS(Status))
5538 {
5539 ExFreePoolWithTag(Info, GDITAG_TEXT);
5540 EngSetLastError(ERROR_INVALID_PARAMETER);
5541 return -1;
5542 }
5543 }
5544
5545 ExFreePoolWithTag(Info, GDITAG_TEXT);
5546
5547 return Count;
5548 }
5549
5550 FORCEINLINE
5551 LONG
5552 ScaleLong(LONG lValue, PFLOATOBJ pef)
5553 {
5554 FLOATOBJ efTemp;
5555
5556 /* Check if we have scaling different from 1 */
5557 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
5558 {
5559 /* Need to multiply */
5560 FLOATOBJ_SetLong(&efTemp, lValue);
5561 FLOATOBJ_Mul(&efTemp, pef);
5562 lValue = FLOATOBJ_GetLong(&efTemp);
5563 }
5564
5565 return lValue;
5566 }
5567
5568 BOOL
5569 APIENTRY
5570 GreExtTextOutW(
5571 IN HDC hDC,
5572 IN INT XStart,
5573 IN INT YStart,
5574 IN UINT fuOptions,
5575 IN OPTIONAL PRECTL lprc,
5576 IN LPCWSTR String,
5577 IN INT Count,
5578 IN OPTIONAL LPINT Dx,
5579 IN DWORD dwCodePage)
5580 {
5581 /*
5582 * FIXME:
5583 * Call EngTextOut, which does the real work (calling DrvTextOut where
5584 * appropriate)
5585 */
5586
5587 DC *dc;
5588 PDC_ATTR pdcattr;
5589 SURFOBJ *SurfObj;
5590 SURFACE *psurf = NULL;
5591 int error, glyph_index, i;
5592 FT_Face face;
5593 FT_GlyphSlot glyph;
5594 FT_BitmapGlyph realglyph;
5595 LONGLONG TextLeft, RealXStart;
5596 ULONG TextTop, previous;
5597 FT_Bool use_kerning;
5598 RECTL DestRect, MaskRect;
5599 POINTL SourcePoint, BrushOrigin;
5600 HBITMAP HSourceGlyph;
5601 SURFOBJ *SourceGlyphSurf;
5602 SIZEL bitSize;
5603 INT yoff;
5604 FONTOBJ *FontObj;
5605 PFONTGDI FontGDI;
5606 PTEXTOBJ TextObj = NULL;
5607 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
5608 FT_Render_Mode RenderMode;
5609 BOOLEAN Render;
5610 POINT Start;
5611 BOOL DoBreak = FALSE;
5612 USHORT DxShift;
5613 PMATRIX pmxWorldToDevice;
5614 LONG fixAscender, fixDescender;
5615 FLOATOBJ Scale;
5616 LOGFONTW *plf;
5617 BOOL EmuBold, EmuItalic;
5618 int thickness;
5619 BOOL bResult;
5620 ULONGLONG TextWidth;
5621
5622 /* Check if String is valid */
5623 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
5624 {
5625 EngSetLastError(ERROR_INVALID_PARAMETER);
5626 return FALSE;
5627 }
5628
5629 /* NOTE: This function locks the screen DC, so it must never be called
5630 with a DC already locked */
5631 Render = IntIsFontRenderingEnabled();
5632
5633 // TODO: Write test-cases to exactly match real Windows in different
5634 // bad parameters (e.g. does Windows check the DC or the RECT first?).
5635 dc = DC_LockDc(hDC);
5636 if (!dc)
5637 {
5638 EngSetLastError(ERROR_INVALID_HANDLE);
5639 return FALSE;
5640 }
5641
5642 if (PATH_IsPathOpen(dc->dclevel))
5643 {
5644 bResult = PATH_ExtTextOut(dc,
5645 XStart,
5646 YStart,
5647 fuOptions,
5648 (const RECTL *)lprc,
5649 String,
5650 Count,
5651 (const INT *)Dx);
5652 DC_UnlockDc(dc);
5653 return bResult;
5654 }
5655
5656 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
5657
5658 if (!dc->dclevel.pSurface)
5659 {
5660 /* Memory DC with no surface selected */
5661 bResult = TRUE;
5662 goto Cleanup;
5663 }
5664
5665 pdcattr = dc->pdcattr;
5666
5667 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
5668 {
5669 IntLPtoDP(dc, (POINT *)lprc, 2);
5670 }
5671
5672 if (pdcattr->lTextAlign & TA_UPDATECP)
5673 {
5674 Start.x = pdcattr->ptlCurrent.x;
5675 Start.y = pdcattr->ptlCurrent.y;
5676 } else {
5677 Start.x = XStart;
5678 Start.y = YStart;
5679 }
5680
5681 IntLPtoDP(dc, &Start, 1);
5682 RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
5683 YStart = Start.y + dc->ptlDCOrig.y;
5684
5685 SourcePoint.x = 0;
5686 SourcePoint.y = 0;
5687 MaskRect.left = 0;
5688 MaskRect.top = 0;
5689 BrushOrigin.x = 0;
5690 BrushOrigin.y = 0;
5691
5692 if ((fuOptions & ETO_OPAQUE) && lprc)
5693 {
5694 DestRect.left = lprc->left;
5695 DestRect.top = lprc->top;
5696 DestRect.right = lprc->right;
5697 DestRect.bottom = lprc->bottom;
5698
5699 DestRect.left += dc->ptlDCOrig.x;
5700 DestRect.top += dc->ptlDCOrig.y;
5701 DestRect.right += dc->ptlDCOrig.x;
5702 DestRect.bottom += dc->ptlDCOrig.y;
5703
5704 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5705 {
5706 IntUpdateBoundsRect(dc, &DestRect);
5707 }
5708
5709 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5710 DC_vUpdateBackgroundBrush(dc);
5711 if (dc->dctype == DCTYPE_DIRECT)
5712 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5713
5714 psurf = dc->dclevel.pSurface;
5715 IntEngBitBlt(
5716 &psurf->SurfObj,
5717 NULL,
5718 NULL,
5719 (CLIPOBJ *)&dc->co,
5720 NULL,
5721 &DestRect,
5722 &SourcePoint,
5723 &SourcePoint,
5724 &dc->eboBackground.BrushObject,
5725 &BrushOrigin,
5726 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5727
5728 if (dc->dctype == DCTYPE_DIRECT)
5729 MouseSafetyOnDrawEnd(dc->ppdev);
5730
5731 fuOptions &= ~ETO_OPAQUE;
5732 }
5733 else
5734 {
5735 if (pdcattr->jBkMode == OPAQUE)
5736 {
5737 fuOptions |= ETO_OPAQUE;
5738 }
5739 }
5740
5741 TextObj = RealizeFontInit(pdcattr->hlfntNew);
5742 if (TextObj == NULL)
5743 {
5744 bResult = FALSE;
5745 goto Cleanup;
5746 }
5747
5748 FontObj = TextObj->Font;
5749 ASSERT(FontObj);
5750 FontGDI = ObjToGDI(FontObj, FONT);
5751 ASSERT(FontGDI);
5752
5753 IntLockFreeType();
5754 face = FontGDI->SharedFace->Face;
5755
5756 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5757 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
5758 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
5759
5760 if (Render)
5761 RenderMode = IntGetFontRenderMode(plf);
5762 else
5763 RenderMode = FT_RENDER_MODE_MONO;
5764
5765 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
5766 {
5767 IntUnLockFreeType();
5768 bResult = FALSE;
5769 goto Cleanup;
5770 }
5771
5772 /* NOTE: Don't trust face->size->metrics.ascender and descender values. */
5773 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
5774 {
5775 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
5776 FtSetCoordinateTransform(face, pmxWorldToDevice);
5777
5778 fixAscender = ScaleLong(FontGDI->tmAscent, &pmxWorldToDevice->efM22) << 6;
5779 fixDescender = ScaleLong(FontGDI->tmDescent, &pmxWorldToDevice->efM22) << 6;
5780 }
5781 else
5782 {
5783 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
5784 FtSetCoordinateTransform(face, pmxWorldToDevice);
5785
5786 fixAscender = FontGDI->tmAscent << 6;
5787 fixDescender = FontGDI->tmDescent << 6;
5788 }
5789
5790 /*
5791 * Process the vertical alignment and determine the yoff.
5792 */
5793 #define VALIGN_MASK (TA_TOP | TA_BASELINE | TA_BOTTOM)
5794 if ((pdcattr->lTextAlign & VALIGN_MASK) == TA_BASELINE)
5795 yoff = 0;
5796 else if ((pdcattr->lTextAlign & VALIGN_MASK) == TA_BOTTOM)
5797 yoff = -(fixDescender >> 6);
5798 else /* TA_TOP */
5799 yoff = fixAscender >> 6;
5800 #undef VALIGN_MASK
5801
5802 /*
5803 * Calculate width of the text.
5804 */
5805 TextWidth = 0;
5806 DxShift = fuOptions & ETO_PDY ? 1 : 0;
5807 use_kerning = FT_HAS_KERNING(face);
5808 previous = 0;
5809 if ((fuOptions & ETO_OPAQUE) ||
5810 (pdcattr->lTextAlign & (TA_CENTER | TA_RIGHT)))
5811 {
5812 TextLeft = RealXStart;
5813 TextTop = YStart;
5814 for (i = 0; i < Count; ++i)
5815 {
5816 glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions);
5817
5818 // FIXME: Use FT_LOAD_BITMAP_METRICS_ONLY or cache.
5819 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5820 if (error)
5821 {
5822 DPRINT1("Failed to load glyph! [index: %d]\n", glyph_index);
5823 IntUnLockFreeType();
5824 bResult = FALSE;
5825 goto Cleanup;
5826 }
5827
5828 glyph = face->glyph;
5829 if (EmuBold)
5830 FT_GlyphSlot_Embolden(glyph);
5831 if (EmuItalic)
5832 FT_GlyphSlot_Oblique(glyph);
5833 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5834 if (!realglyph)
5835 {
5836 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5837 IntUnLockFreeType();
5838 bResult = FALSE;
5839 goto Cleanup;
5840 }
5841
5842 /* retrieve kerning distance and move pen position */
5843 if (use_kerning && previous && glyph_index && Dx == NULL)
5844 {
5845 FT_Vector delta;
5846 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5847 TextLeft += delta.x;
5848 }
5849
5850 if (Dx == NULL)
5851 {
5852 TextLeft += realglyph->root.advance.x >> 10;
5853 }
5854 else
5855 {
5856 // FIXME this should probably be a matrix transform with TextTop as well.
5857 Scale = pdcattr->mxWorldToDevice.efM11;
5858 if (FLOATOBJ_Equal0(&Scale))
5859 FLOATOBJ_Set1(&Scale);
5860
5861 /* do the shift before multiplying to preserve precision */
5862 FLOATOBJ_MulLong(&Scale, Dx[i << DxShift] << 6);
5863 TextLeft += FLOATOBJ_GetLong(&Scale);
5864 }
5865
5866 if (DxShift)
5867 {
5868 TextTop -= Dx[2 * i + 1] << 6;
5869 }
5870
5871 previous = glyph_index;
5872
5873 if (EmuBold || EmuItalic)
5874 {
5875 FT_Done_Glyph((FT_Glyph)realglyph);
5876 realglyph = NULL;
5877 }
5878 }
5879
5880 TextWidth = TextLeft - RealXStart;
5881 }
5882
5883 /*
5884 * Process the horizontal alignment and modify XStart accordingly.
5885 */
5886 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
5887 {
5888 RealXStart -= TextWidth / 2;
5889 }
5890 else if ((pdcattr->lTextAlign & TA_RIGHT) == TA_RIGHT)
5891 {
5892 RealXStart -= TextWidth;
5893 if (((RealXStart + TextWidth + 32) >> 6) <= Start.x + dc->ptlDCOrig.x)
5894 RealXStart += 1 << 6;
5895 }
5896
5897 psurf = dc->dclevel.pSurface;
5898 SurfObj = &psurf->SurfObj ;
5899
5900 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
5901 DC_vUpdateBackgroundBrush(dc) ;
5902
5903 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
5904 DC_vUpdateTextBrush(dc) ;
5905
5906 if (!face->units_per_EM)
5907 {
5908 thickness = 1;
5909 }
5910 else
5911 {
5912 thickness = face->underline_thickness *
5913 face->size->metrics.y_ppem / face->units_per_EM;
5914 if (thickness <= 0)
5915 thickness = 1;
5916 }
5917
5918 if (fuOptions & ETO_OPAQUE)
5919 {
5920 /* Draw background */
5921 RECTL Rect;
5922
5923 Rect.left = (RealXStart + 32) >> 6;
5924 Rect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5925 Rect.right = (RealXStart + TextWidth + 32) >> 6;
5926 Rect.bottom = Rect.top + ((fixAscender + fixDescender) >> 6);
5927
5928 if (dc->fs & (DC_ACCUM_APP | DC_ACCUM_WMGR))
5929 {
5930 IntUpdateBoundsRect(dc, &Rect);
5931 }
5932
5933 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5934 DC_vUpdateBackgroundBrush(dc);
5935 if (dc->dctype == DCTYPE_DIRECT)
5936 MouseSafetyOnDrawStart(dc->ppdev, Rect.left, Rect.top, Rect.right, Rect.bottom);
5937
5938 SourcePoint.x = SourcePoint.y = 0;
5939 BrushOrigin.x = BrushOrigin.y = 0;
5940
5941 psurf = dc->dclevel.pSurface;
5942 IntEngBitBlt(
5943 &psurf->SurfObj,
5944 NULL,
5945 NULL,
5946 (CLIPOBJ *)&dc->co,
5947 NULL,
5948 &Rect,
5949 &SourcePoint,
5950 &SourcePoint,
5951 &dc->eboBackground.BrushObject,
5952 &BrushOrigin,
5953 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5954
5955 if (dc->dctype == DCTYPE_DIRECT)
5956 MouseSafetyOnDrawEnd(dc->ppdev);
5957 }
5958
5959 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
5960 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
5961
5962 /* Assume success */
5963 bResult = TRUE;
5964
5965 /*
5966 * The main rendering loop.
5967 */
5968 TextLeft = RealXStart;
5969 TextTop = YStart;
5970 previous = 0;
5971 for (i = 0; i < Count; ++i)
5972 {
5973 glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions);
5974
5975 if (EmuBold || EmuItalic)
5976 realglyph = NULL;
5977 else
5978 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
5979 RenderMode, pmxWorldToDevice);
5980 if (!realglyph)
5981 {
5982 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5983 if (error)
5984 {
5985 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5986 bResult = FALSE;
5987 break;
5988 }
5989
5990 glyph = face->glyph;
5991 if (EmuBold || EmuItalic)
5992 {
5993 if (EmuBold)
5994 FT_GlyphSlot_Embolden(glyph);
5995 if (EmuItalic)
5996 FT_GlyphSlot_Oblique(glyph);
5997 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5998 }
5999 else
6000 {
6001 realglyph = ftGdiGlyphCacheSet(face,
6002 glyph_index,
6003 plf->lfHeight,
6004 pmxWorldToDevice,
6005 glyph,
6006 RenderMode);
6007 }
6008 if (!realglyph)
6009 {
6010 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
6011 bResult = FALSE;
6012 break;
6013 }
6014 }
6015
6016 /* retrieve kerning distance and move pen position */
6017 if (use_kerning && previous && glyph_index && NULL == Dx)
6018 {
6019 FT_Vector delta;
6020 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
6021 TextLeft += delta.x;
6022 }
6023 DPRINT("TextLeft: %I64d\n", TextLeft);
6024 DPRINT("TextTop: %lu\n", TextTop);
6025 DPRINT("Advance: %d\n", realglyph->root.advance.x);
6026
6027 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
6028 DestRect.right = DestRect.left + realglyph->bitmap.width;
6029 DestRect.top = TextTop + yoff - realglyph->top;
6030 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
6031
6032 bitSize.cx = realglyph->bitmap.width;
6033 bitSize.cy = realglyph->bitmap.rows;
6034 MaskRect.right = realglyph->bitmap.width;
6035 MaskRect.bottom = realglyph->bitmap.rows;
6036
6037 /* Check if the bitmap has any pixels */
6038 if ((bitSize.cx != 0) && (bitSize.cy != 0))
6039 {
6040 /*
6041 * We should create the bitmap out of the loop at the biggest possible
6042 * glyph size. Then use memset with 0 to clear it and sourcerect to
6043 * limit the work of the transbitblt.
6044 */
6045 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
6046 BMF_8BPP, BMF_TOPDOWN,
6047 realglyph->bitmap.buffer);
6048 if ( !HSourceGlyph )
6049 {
6050 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
6051 // FT_Done_Glyph(realglyph);
6052 bResult = FALSE;
6053 break;
6054 }
6055 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
6056 if ( !SourceGlyphSurf )
6057 {
6058 EngDeleteSurface((HSURF)HSourceGlyph);
6059 DPRINT1("WARNING: EngLockSurface() failed!\n");
6060 bResult = FALSE;
6061 break;
6062 }
6063
6064 /*
6065 * Use the font data as a mask to paint onto the DCs surface using a
6066 * brush.
6067 */
6068 if (lprc && (fuOptions & ETO_CLIPPED) &&
6069 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
6070 {
6071 // We do the check '>=' instead of '>' to possibly save an iteration
6072 // through this loop, since it's breaking after the drawing is done,
6073 // and x is always incremented.
6074 DestRect.right = lprc->right + dc->ptlDCOrig.x;
6075 DoBreak = TRUE;
6076 }
6077 if (lprc && (fuOptions & ETO_CLIPPED) &&
6078 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
6079 {
6080 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
6081 }
6082
6083 if (dc->dctype == DCTYPE_DIRECT)
6084 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
6085
6086 if (!IntEngMaskBlt(
6087 SurfObj,
6088 SourceGlyphSurf,
6089 (CLIPOBJ *)&dc->co,
6090 &exloRGB2Dst.xlo,
6091 &exloDst2RGB.xlo,
6092 &DestRect,
6093 (PPOINTL)&MaskRect,
6094 &dc->eboText.BrushObject,
6095 &BrushOrigin))
6096 {
6097 DPRINT1("Failed to MaskBlt a glyph!\n");
6098 }
6099
6100 if (dc->dctype == DCTYPE_DIRECT)
6101 MouseSafetyOnDrawEnd(dc->ppdev) ;
6102
6103 EngUnlockSurface(SourceGlyphSurf);
6104 EngDeleteSurface((HSURF)HSourceGlyph);
6105 }
6106
6107 if (DoBreak)
6108 {
6109 break;
6110 }
6111
6112 if (plf->lfUnderline)
6113 {
6114 int i, position;
6115 if (!face->units_per_EM)
6116 {
6117 position = 0;
6118 }
6119 else
6120 {
6121 position = face->underline_position *
6122 face->size->metrics.y_ppem / face->units_per_EM;
6123 }
6124 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
6125 {
6126 EngLineTo(SurfObj,
6127 (CLIPOBJ *)&dc->co,
6128 &dc->eboText.BrushObject,
6129 (TextLeft >> 6),
6130 TextTop + yoff - position + i,
6131 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
6132 TextTop + yoff - position + i,
6133 NULL,
6134 ROP2_TO_MIX(R2_COPYPEN));
6135 }
6136 }
6137 if (plf->lfStrikeOut)
6138 {
6139 int i;
6140 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
6141 {
6142 EngLineTo(SurfObj,
6143 (CLIPOBJ *)&dc->co,
6144 &dc->eboText.BrushObject,
6145 (TextLeft >> 6),
6146 TextTop + yoff - (fixAscender >> 6) / 3 + i,
6147 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
6148 TextTop + yoff - (fixAscender >> 6) / 3 + i,
6149 NULL,
6150 ROP2_TO_MIX(R2_COPYPEN));
6151 }
6152 }
6153
6154 if (NULL == Dx)
6155 {
6156 TextLeft += realglyph->root.advance.x >> 10;
6157 DPRINT("New TextLeft: %I64d\n", TextLeft);
6158 }
6159 else
6160 {
6161 // FIXME this should probably be a matrix transform with TextTop as well.
6162 Scale = pdcattr->mxWorldToDevice.efM11;
6163 if (FLOATOBJ_Equal0(&Scale))
6164 FLOATOBJ_Set1(&Scale);
6165
6166 /* do the shift before multiplying to preserve precision */
6167 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
6168 TextLeft += FLOATOBJ_GetLong(&Scale);
6169 DPRINT("New TextLeft2: %I64d\n", TextLeft);
6170 }
6171
6172 if (DxShift)
6173 {
6174 TextTop -= Dx[2 * i + 1] << 6;
6175 }
6176
6177 previous = glyph_index;
6178
6179 if (EmuBold || EmuItalic)
6180 {
6181 FT_Done_Glyph((FT_Glyph)realglyph);
6182 realglyph = NULL;
6183 }
6184 }
6185
6186 if (pdcattr->lTextAlign & TA_UPDATECP) {
6187 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
6188 }
6189
6190 IntUnLockFreeType();
6191
6192 EXLATEOBJ_vCleanup(&exloRGB2Dst);
6193 EXLATEOBJ_vCleanup(&exloDst2RGB);
6194
6195 Cleanup:
6196
6197 DC_vFinishBlit(dc, NULL);
6198
6199 if (TextObj != NULL)
6200 TEXTOBJ_UnlockText(TextObj);
6201
6202 DC_UnlockDc(dc);
6203
6204 return bResult;
6205 }
6206
6207 #define STACK_TEXT_BUFFER_SIZE 100
6208 BOOL
6209 APIENTRY
6210 NtGdiExtTextOutW(
6211 IN HDC hDC,
6212 IN INT XStart,
6213 IN INT YStart,
6214 IN UINT fuOptions,
6215 IN OPTIONAL LPRECT UnsafeRect,
6216 IN LPWSTR UnsafeString,
6217 IN INT Count,
6218 IN OPTIONAL LPINT UnsafeDx,
6219 IN DWORD dwCodePage)
6220 {
6221 BOOL Result = FALSE;
6222 NTSTATUS Status = STATUS_SUCCESS;
6223 RECTL SafeRect;
6224 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
6225 PVOID Buffer = LocalBuffer;
6226 LPCWSTR SafeString = NULL;
6227 LPINT SafeDx = NULL;
6228 ULONG BufSize, StringSize, DxSize = 0;
6229
6230 /* Check if String is valid */
6231 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
6232 {
6233 EngSetLastError(ERROR_INVALID_PARAMETER);
6234 return FALSE;
6235 }
6236
6237 if (Count > 0)
6238 {
6239 /* Calculate buffer size for string and Dx values */
6240 BufSize = StringSize = Count * sizeof(WCHAR);
6241 if (UnsafeDx)
6242 {
6243 /* If ETO_PDY is specified, we have pairs of INTs */
6244 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
6245 BufSize += DxSize;
6246 }
6247
6248 /* Check if our local buffer is large enough */
6249 if (BufSize > STACK_TEXT_BUFFER_SIZE)
6250 {
6251 /* It's not, allocate a temp buffer */
6252 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
6253 if (!Buffer)
6254 {
6255 return FALSE;
6256 }
6257 }
6258
6259 /* Probe and copy user mode data to the buffer */
6260 _SEH2_TRY
6261 {
6262 /* Put the Dx before the String to assure alignment of 4 */
6263 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
6264
6265 /* Probe and copy the string */
6266 ProbeForRead(UnsafeString, StringSize, 1);
6267 memcpy((PVOID)SafeString, UnsafeString, StringSize);
6268
6269 /* If we have Dx values... */
6270 if (UnsafeDx)
6271 {
6272 /* ... probe and copy them */
6273 SafeDx = Buffer;
6274 ProbeForRead(UnsafeDx, DxSize, 1);
6275 memcpy(SafeDx, UnsafeDx, DxSize);
6276 }
6277 }
6278 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6279 {
6280 Status = _SEH2_GetExceptionCode();
6281 }
6282 _SEH2_END
6283 if (!NT_SUCCESS(Status))
6284 {
6285 goto cleanup;
6286 }
6287 }
6288
6289 /* If we have a rect, copy it */
6290 if (UnsafeRect)
6291 {
6292 _SEH2_TRY
6293 {
6294 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
6295 SafeRect = *UnsafeRect;
6296 }
6297 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6298 {
6299 Status = _SEH2_GetExceptionCode();
6300 }
6301 _SEH2_END
6302 if (!NT_SUCCESS(Status))
6303 {
6304 goto cleanup;
6305 }
6306 }
6307
6308 /* Finally call the internal routine */
6309 Result = GreExtTextOutW(hDC,
6310 XStart,
6311 YStart,
6312 fuOptions,
6313 &SafeRect,
6314 SafeString,
6315 Count,
6316 SafeDx,
6317 dwCodePage);
6318
6319 cleanup:
6320 /* If we allocated a buffer, free it */
6321 if (Buffer != LocalBuffer)
6322 {
6323 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6324 }
6325
6326 return Result;
6327 }
6328
6329
6330 /*
6331 * @implemented
6332 */
6333 BOOL
6334 APIENTRY
6335 NtGdiGetCharABCWidthsW(
6336 IN HDC hDC,
6337 IN UINT FirstChar,
6338 IN ULONG Count,
6339 IN OPTIONAL PWCHAR UnSafepwch,
6340 IN FLONG fl,
6341 OUT PVOID Buffer)
6342 {
6343 LPABC SafeBuff;
6344 LPABCFLOAT SafeBuffF = NULL;
6345 PDC dc;
6346 PDC_ATTR pdcattr;
6347 PTEXTOBJ TextObj;
6348 PFONTGDI FontGDI;
6349 FT_Face face;
6350 FT_CharMap charmap, found = NULL;
6351 UINT i, glyph_index, BufferSize;
6352 HFONT hFont = 0;
6353 NTSTATUS Status = STATUS_SUCCESS;
6354 PMATRIX pmxWorldToDevice;
6355 PWCHAR Safepwch = NULL;
6356 LOGFONTW *plf;
6357
6358 if (!Buffer)
6359 {
6360 EngSetLastError(ERROR_INVALID_PARAMETER);
6361 return FALSE;
6362 }
6363
6364 if (UnSafepwch)
6365 {
6366 UINT pwchSize = Count * sizeof(WCHAR);
6367 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
6368
6369 if(!Safepwch)
6370 {
6371 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6372 return FALSE;
6373 }
6374
6375 _SEH2_TRY
6376 {
6377 ProbeForRead(UnSafepwch, pwchSize, 1);
6378 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
6379 }
6380 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6381 {
6382 Status = _SEH2_GetExceptionCode();
6383 }
6384 _SEH2_END;
6385 }
6386
6387 if (!NT_SUCCESS(Status))
6388 {
6389 if(Safepwch)
6390 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6391
6392 EngSetLastError(Status);
6393 return FALSE;
6394 }
6395
6396 BufferSize = Count * sizeof(ABC); // Same size!
6397 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6398 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
6399 if (SafeBuff == NULL)
6400 {
6401
6402 if(Safepwch)
6403 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6404
6405 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6406 return FALSE;
6407 }
6408
6409 dc = DC_LockDc(hDC);
6410 if (dc == NULL)
6411 {
6412 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6413
6414 if(Safepwch)
6415 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6416
6417 EngSetLastError(ERROR_INVALID_HANDLE);
6418 return FALSE;
6419 }
6420 pdcattr = dc->pdcattr;
6421 hFont = pdcattr->hlfntNew;
6422 TextObj = RealizeFontInit(hFont);
6423
6424 /* Get the DC's world-to-device transformation matrix */
6425 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6426 DC_UnlockDc(dc);
6427
6428 if (TextObj == NULL)
6429 {
6430 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6431
6432 if(Safepwch)
6433 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6434
6435 EngSetLastError(ERROR_INVALID_HANDLE);
6436 return FALSE;
6437 }
6438
6439 FontGDI = ObjToGDI(TextObj->Font, FONT);
6440
6441 face = FontGDI->SharedFace->Face;
6442 if (face->charmap == NULL)
6443 {
6444 for (i = 0; i < (UINT)face->num_charmaps; i++)
6445 {
6446 charmap = face->charmaps[i];
6447 if (charmap->encoding != 0)
6448 {
6449 found = charmap;
6450 break;
6451 }
6452 }
6453
6454 if (!found)
6455 {
6456 DPRINT1("WARNING: Could not find desired charmap!\n");
6457 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6458
6459 if(Safepwch)
6460 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6461
6462 EngSetLastError(ERROR_INVALID_HANDLE);
6463 return FALSE;
6464 }
6465
6466 IntLockFreeType();
6467 FT_Set_Charmap(face, found);
6468 IntUnLockFreeType();
6469 }
6470
6471 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6472 IntLockFreeType();
6473 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
6474 FtSetCoordinateTransform(face, pmxWorldToDevice);
6475
6476 for (i = FirstChar; i < FirstChar+Count; i++)
6477 {
6478 int adv, lsb, bbx, left, right;
6479
6480 if (Safepwch)
6481 {
6482 glyph_index = get_glyph_index_flagged(face, Safepwch[i - FirstChar], GCABCW_INDICES, fl);
6483 }
6484 else
6485 {
6486 glyph_index = get_glyph_index_flagged(face, i, GCABCW_INDICES, fl);
6487 }
6488 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6489
6490 left = (INT)face->glyph->metrics.horiBearingX & -64;
6491 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
6492 adv = (face->glyph->advance.x + 32) >> 6;
6493
6494 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
6495 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
6496
6497 lsb = left >> 6;
6498 bbx = (right - left) >> 6;
6499 /*
6500 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
6501 */
6502 if (!fl)
6503 {
6504 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
6505 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
6506 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
6507 }
6508 else
6509 {
6510 SafeBuff[i - FirstChar].abcA = lsb;
6511 SafeBuff[i - FirstChar].abcB = bbx;
6512 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
6513 }
6514 }
6515 IntUnLockFreeType();
6516 TEXTOBJ_UnlockText(TextObj);
6517 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6518
6519 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6520
6521 if(Safepwch)
6522 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6523
6524 if (! NT_SUCCESS(Status))
6525 {
6526 SetLastNtError(Status);
6527 return FALSE;
6528 }
6529
6530 DPRINT("NtGdiGetCharABCWidths Worked!\n");
6531 return TRUE;
6532 }
6533
6534 /*
6535 * @implemented
6536 */
6537 BOOL
6538 APIENTRY
6539 NtGdiGetCharWidthW(
6540 IN HDC hDC,
6541 IN UINT FirstChar,
6542 IN UINT Count,
6543 IN OPTIONAL PWCHAR UnSafepwc,
6544 IN FLONG fl,
6545 OUT PVOID Buffer)
6546 {
6547 NTSTATUS Status = STATUS_SUCCESS;
6548 LPINT SafeBuff;
6549 PFLOAT SafeBuffF = NULL;
6550 PDC dc;
6551 PDC_ATTR pdcattr;
6552 PTEXTOBJ TextObj;
6553 PFONTGDI FontGDI;
6554 FT_Face face;
6555 FT_CharMap charmap, found = NULL;
6556 UINT i, glyph_index, BufferSize;
6557 HFONT hFont = 0;
6558 PMATRIX pmxWorldToDevice;
6559 PWCHAR Safepwc = NULL;
6560 LOGFONTW *plf;
6561
6562 if (UnSafepwc)
6563 {
6564 UINT pwcSize = Count * sizeof(WCHAR);
6565 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6566
6567 if(!Safepwc)
6568 {
6569 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6570 return FALSE;
6571 }
6572 _SEH2_TRY
6573 {
6574 ProbeForRead(UnSafepwc, pwcSize, 1);
6575 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6576 }
6577 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6578 {
6579 Status = _SEH2_GetExceptionCode();
6580 }
6581 _SEH2_END;
6582 }
6583
6584 if (!NT_SUCCESS(Status))
6585 {
6586 EngSetLastError(Status);
6587 return FALSE;
6588 }
6589
6590 BufferSize = Count * sizeof(INT); // Same size!
6591 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6592 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
6593 if (SafeBuff == NULL)
6594 {
6595 if(Safepwc)
6596 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6597
6598 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6599 return FALSE;
6600 }
6601
6602 dc = DC_LockDc(hDC);
6603 if (dc == NULL)
6604 {
6605 if(Safepwc)
6606 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6607
6608 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6609 EngSetLastError(ERROR_INVALID_HANDLE);
6610 return FALSE;
6611 }
6612 pdcattr = dc->pdcattr;
6613 hFont = pdcattr->hlfntNew;
6614 TextObj = RealizeFontInit(hFont);
6615 /* Get the DC's world-to-device transformation matrix */
6616 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6617 DC_UnlockDc(dc);
6618
6619 if (TextObj == NULL)
6620 {
6621 if(Safepwc)
6622 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6623
6624 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6625 EngSetLastError(ERROR_INVALID_HANDLE);
6626 return FALSE;
6627 }
6628
6629 FontGDI = ObjToGDI(TextObj->Font, FONT);
6630
6631 face = FontGDI->SharedFace->Face;
6632 if (face->charmap == NULL)
6633 {
6634 for (i = 0; i < (UINT)face->num_charmaps; i++)
6635 {
6636 charmap = face->charmaps[i];
6637 if (charmap->encoding != 0)
6638 {
6639 found = charmap;
6640 break;
6641 }
6642 }
6643
6644 if (!found)
6645 {
6646 DPRINT1("WARNING: Could not find desired charmap!\n");
6647
6648 if(Safepwc)
6649 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6650
6651 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6652 EngSetLastError(ERROR_INVALID_HANDLE);
6653 return FALSE;
6654 }
6655
6656 IntLockFreeType();
6657 FT_Set_Charmap(face, found);
6658 IntUnLockFreeType();
6659 }
6660
6661 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6662 IntLockFreeType();
6663 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
6664 FtSetCoordinateTransform(face, pmxWorldToDevice);
6665
6666 for (i = FirstChar; i < FirstChar+Count; i++)
6667 {
6668 if (Safepwc)
6669 {
6670 glyph_index = get_glyph_index_flagged(face, Safepwc[i - FirstChar], GCW_INDICES, fl);
6671 }
6672 else
6673 {
6674 glyph_index = get_glyph_index_flagged(face, i, GCW_INDICES, fl);
6675 }
6676 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6677 if (!fl)
6678 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
6679 else
6680 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
6681 }
6682 IntUnLockFreeType();
6683 TEXTOBJ_UnlockText(TextObj);
6684 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6685
6686 if(Safepwc)
6687 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6688
6689 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6690 return TRUE;
6691 }
6692
6693
6694 /*
6695 * @implemented
6696 */
6697 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
6698 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
6699 // NOTE: See also GreGetGlyphIndicesW.
6700 __kernel_entry
6701 W32KAPI
6702 DWORD
6703 APIENTRY
6704 NtGdiGetGlyphIndicesW(
6705 _In_ HDC hdc,
6706 _In_reads_opt_(cwc) LPCWSTR pwc,
6707 _In_ INT cwc,
6708 _Out_writes_opt_(cwc) LPWORD pgi,
6709 _In_ DWORD iMode)
6710 {
6711 PDC dc;
6712 PDC_ATTR pdcattr;
6713 PTEXTOBJ TextObj;
6714 PFONTGDI FontGDI;
6715 HFONT hFont = NULL;
6716 NTSTATUS Status = STATUS_SUCCESS;
6717 OUTLINETEXTMETRICW *potm;
6718 INT i;
6719 WCHAR DefChar = 0xffff;
6720 PWSTR Buffer = NULL;
6721 ULONG Size, pwcSize;
6722 PWSTR Safepwc = NULL;
6723 LPCWSTR UnSafepwc = pwc;
6724 LPWORD UnSafepgi = pgi;
6725
6726 /* Check for integer overflow */
6727 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN
6728 return GDI_ERROR;
6729
6730 if (!UnSafepwc && !UnSafepgi)
6731 return cwc;
6732
6733 if (!UnSafepwc || !UnSafepgi)
6734 {
6735 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
6736 return GDI_ERROR;
6737 }
6738
6739 // TODO: Special undocumented case!
6740 if (!pwc && !pgi && (cwc == 0))
6741 {
6742 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n");
6743 return 0;
6744 }
6745
6746 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825
6747 if (cwc == 0)
6748 {
6749 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n");
6750 return GDI_ERROR;
6751 }
6752
6753 dc = DC_LockDc(hdc);
6754 if (!dc)
6755 {
6756 return GDI_ERROR;
6757 }
6758 pdcattr = dc->pdcattr;
6759 hFont = pdcattr->hlfntNew;
6760 TextObj = RealizeFontInit(hFont);
6761 DC_UnlockDc(dc);
6762 if (!TextObj)
6763 {
6764 return GDI_ERROR;
6765 }
6766
6767 FontGDI = ObjToGDI(TextObj->Font, FONT);
6768 TEXTOBJ_UnlockText(TextObj);
6769
6770 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
6771 if (!Buffer)
6772 {
6773 return GDI_ERROR;
6774 }
6775
6776 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
6777 {
6778 DefChar = 0xffff;
6779 }
6780 else
6781 {
6782 FT_Face Face = FontGDI->SharedFace->Face;
6783 if (FT_IS_SFNT(Face))
6784 {
6785 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
6786 DefChar = (pOS2->usDefaultChar ? get_glyph_index(Face, pOS2->usDefaultChar) : 0);
6787 }
6788 else
6789 {
6790 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
6791 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
6792 if (!potm)
6793 {
6794 cwc = GDI_ERROR;
6795 goto ErrorRet;
6796 }
6797 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
6798 if (Size)
6799 DefChar = potm->otmTextMetrics.tmDefaultChar;
6800 ExFreePoolWithTag(potm, GDITAG_TEXT);
6801 }
6802 }
6803
6804 pwcSize = cwc * sizeof(WCHAR);
6805 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6806
6807 if (!Safepwc)
6808 {
6809 Status = STATUS_NO_MEMORY;
6810 goto ErrorRet;
6811 }
6812
6813 _SEH2_TRY
6814 {
6815 ProbeForRead(UnSafepwc, pwcSize, 1);
6816 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6817 }
6818 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6819 {
6820 Status = _SEH2_GetExceptionCode();
6821 }
6822 _SEH2_END;
6823
6824 if (!NT_SUCCESS(Status)) goto ErrorRet;
6825
6826 IntLockFreeType();
6827
6828 for (i = 0; i < cwc; i++)
6829 {
6830 Buffer[i] = get_glyph_index(FontGDI->SharedFace->Face, Safepwc[i]);
6831 if (Buffer[i] == 0)
6832 {
6833 Buffer[i] = DefChar;
6834 }
6835 }
6836
6837 IntUnLockFreeType();
6838
6839 _SEH2_TRY
6840 {
6841 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
6842 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
6843 }
6844 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6845 {
6846 Status = _SEH2_GetExceptionCode();
6847 }
6848 _SEH2_END;
6849
6850 ErrorRet:
6851 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6852 if (Safepwc != NULL)
6853 {
6854 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6855 }
6856 if (NT_SUCCESS(Status)) return cwc;
6857 return GDI_ERROR;
6858 }
6859
6860 /* EOF */