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