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