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