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