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