a74d223cd57f4b2a31fe32a47bf43e49767957f9
[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->efM12;
707 FLOATOBJ_MulLong(&ef, 0x00010000);
708 pmat->xy = FLOATOBJ_GetLong(&ef);
709
710 ef = pmx->efM21;
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, TextWidth64, RealXStart64;
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 INT DY1, DY2;
5559 FT_Matrix mat1, mat2 = identityMat;
5560 FT_Vector vecs[9];
5561 POINT pts[9];
5562
5563 /* Check if String is valid */
5564 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
5565 {
5566 EngSetLastError(ERROR_INVALID_PARAMETER);
5567 return FALSE;
5568 }
5569
5570 /* NOTE: This function locks the screen DC, so it must never be called
5571 with a DC already locked */
5572 Render = IntIsFontRenderingEnabled();
5573
5574 // TODO: Write test-cases to exactly match real Windows in different
5575 // bad parameters (e.g. does Windows check the DC or the RECT first?).
5576 dc = DC_LockDc(hDC);
5577 if (!dc)
5578 {
5579 EngSetLastError(ERROR_INVALID_HANDLE);
5580 return FALSE;
5581 }
5582
5583 if (PATH_IsPathOpen(dc->dclevel))
5584 {
5585 bResult = PATH_ExtTextOut(dc,
5586 XStart,
5587 YStart,
5588 fuOptions,
5589 (const RECTL *)lprc,
5590 String,
5591 Count,
5592 (const INT *)Dx);
5593 DC_UnlockDc(dc);
5594 return bResult;
5595 }
5596
5597 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
5598
5599 if (!dc->dclevel.pSurface)
5600 {
5601 /* Memory DC with no surface selected */
5602 bResult = TRUE;
5603 goto Cleanup;
5604 }
5605
5606 pdcattr = dc->pdcattr;
5607
5608 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
5609 {
5610 IntLPtoDP(dc, (POINT *)lprc, 2);
5611 }
5612
5613 if (pdcattr->lTextAlign & TA_UPDATECP)
5614 {
5615 Start.x = pdcattr->ptlCurrent.x;
5616 Start.y = pdcattr->ptlCurrent.y;
5617 } else {
5618 Start.x = XStart;
5619 Start.y = YStart;
5620 }
5621
5622 IntLPtoDP(dc, &Start, 1);
5623 RealXStart64 = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
5624 YStart = Start.y + dc->ptlDCOrig.y;
5625
5626 SourcePoint.x = 0;
5627 SourcePoint.y = 0;
5628 MaskRect.left = 0;
5629 MaskRect.top = 0;
5630 BrushOrigin.x = 0;
5631 BrushOrigin.y = 0;
5632
5633 if ((fuOptions & ETO_OPAQUE) && lprc)
5634 {
5635 DestRect.left = lprc->left;
5636 DestRect.top = lprc->top;
5637 DestRect.right = lprc->right;
5638 DestRect.bottom = lprc->bottom;
5639
5640 DestRect.left += dc->ptlDCOrig.x;
5641 DestRect.top += dc->ptlDCOrig.y;
5642 DestRect.right += dc->ptlDCOrig.x;
5643 DestRect.bottom += dc->ptlDCOrig.y;
5644
5645 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5646 {
5647 IntUpdateBoundsRect(dc, &DestRect);
5648 }
5649
5650 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5651 DC_vUpdateBackgroundBrush(dc);
5652 if (dc->dctype == DCTYPE_DIRECT)
5653 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5654
5655 psurf = dc->dclevel.pSurface;
5656 IntEngBitBlt(
5657 &psurf->SurfObj,
5658 NULL,
5659 NULL,
5660 (CLIPOBJ *)&dc->co,
5661 NULL,
5662 &DestRect,
5663 &SourcePoint,
5664 &SourcePoint,
5665 &dc->eboBackground.BrushObject,
5666 &BrushOrigin,
5667 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5668
5669 if (dc->dctype == DCTYPE_DIRECT)
5670 MouseSafetyOnDrawEnd(dc->ppdev);
5671
5672 fuOptions &= ~ETO_OPAQUE;
5673 }
5674 else
5675 {
5676 if (pdcattr->jBkMode == OPAQUE)
5677 {
5678 fuOptions |= ETO_OPAQUE;
5679 }
5680 }
5681
5682 TextObj = RealizeFontInit(pdcattr->hlfntNew);
5683 if (TextObj == NULL)
5684 {
5685 bResult = FALSE;
5686 goto Cleanup;
5687 }
5688
5689 FontObj = TextObj->Font;
5690 ASSERT(FontObj);
5691 FontGDI = ObjToGDI(FontObj, FONT);
5692 ASSERT(FontGDI);
5693
5694 IntLockFreeType();
5695 face = FontGDI->SharedFace->Face;
5696
5697 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5698 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
5699 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
5700 if (FT_IS_SCALABLE(face))
5701 {
5702 lfEscapement = IntNormalizeAngle(plf->lfEscapement);
5703 lfWidth = labs(plf->lfWidth);
5704 }
5705 else
5706 {
5707 lfEscapement = lfWidth = 0;
5708 }
5709
5710 if (Render)
5711 RenderMode = IntGetFontRenderMode(plf);
5712 else
5713 RenderMode = FT_RENDER_MODE_MONO;
5714
5715 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
5716 {
5717 IntUnLockFreeType();
5718 bResult = FALSE;
5719 goto Cleanup;
5720 }
5721
5722 /* NOTE: Don't trust face->size->metrics.ascender and descender values. */
5723 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
5724 {
5725 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
5726 FtSetCoordinateTransform(face, pmxWorldToDevice);
5727 }
5728 else
5729 {
5730 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
5731 FtSetCoordinateTransform(face, pmxWorldToDevice);
5732 }
5733
5734 /*
5735 * Process the vertical alignment and determine DY1 and DY2.
5736 */
5737 #define VALIGN_MASK (TA_TOP | TA_BASELINE | TA_BOTTOM)
5738 if ((pdcattr->lTextAlign & VALIGN_MASK) == TA_BASELINE)
5739 {
5740 DY1 = FontGDI->tmAscent;
5741 DY2 = FontGDI->tmDescent;
5742 }
5743 else if ((pdcattr->lTextAlign & VALIGN_MASK) == TA_BOTTOM)
5744 {
5745 DY1 = FontGDI->tmHeight;
5746 DY2 = 0;
5747 }
5748 else /* TA_TOP */
5749 {
5750 DY1 = 0;
5751 DY2 = FontGDI->tmHeight;
5752 }
5753 #undef VALIGN_MASK
5754
5755 IntWidthMatrix(face, &mat1, lfWidth);
5756 FT_Matrix_Multiply(&mat1, &mat2);
5757 FT_Set_Transform(face, &mat2, NULL);
5758
5759 /*
5760 * Calculate width of the text.
5761 */
5762 TextWidth64 = 0;
5763 DxShift = fuOptions & ETO_PDY ? 1 : 0;
5764 use_kerning = FT_HAS_KERNING(face);
5765 previous = 0;
5766 if ((fuOptions & ETO_OPAQUE) ||
5767 (pdcattr->lTextAlign & (TA_CENTER | TA_RIGHT)) ||
5768 lfEscapement || plf->lfUnderline || plf->lfStrikeOut)
5769 {
5770 TextLeft64 = RealXStart64;
5771 TextTop64 = YStart << 6;
5772 for (i = 0; i < Count; ++i)
5773 {
5774 glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions);
5775
5776 // FIXME: Use FT_LOAD_BITMAP_METRICS_ONLY or cache.
5777 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5778 if (error)
5779 {
5780 DPRINT1("Failed to load glyph! [index: %d]\n", glyph_index);
5781 IntUnLockFreeType();
5782 bResult = FALSE;
5783 goto Cleanup;
5784 }
5785
5786 glyph = face->glyph;
5787 if (EmuBold)
5788 FT_GlyphSlot_Embolden(glyph);
5789 if (EmuItalic)
5790 FT_GlyphSlot_Oblique(glyph);
5791 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5792 if (!realglyph)
5793 {
5794 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5795 IntUnLockFreeType();
5796 bResult = FALSE;
5797 goto Cleanup;
5798 }
5799
5800 /* retrieve kerning distance and move pen position */
5801 if (use_kerning && previous && glyph_index && Dx == NULL)
5802 {
5803 FT_Vector delta;
5804 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5805 TextLeft64 += delta.x;
5806 }
5807
5808 if (Dx == NULL)
5809 {
5810 TextLeft64 += realglyph->root.advance.x >> 10;
5811 }
5812 else
5813 {
5814 // FIXME this should probably be a matrix transform with TextTop64 as well.
5815 Scale = pdcattr->mxWorldToDevice.efM11;
5816 if (FLOATOBJ_Equal0(&Scale))
5817 FLOATOBJ_Set1(&Scale);
5818
5819 /* do the shift before multiplying to preserve precision */
5820 FLOATOBJ_MulLong(&Scale, Dx[i << DxShift] << 6);
5821 TextLeft64 += FLOATOBJ_GetLong(&Scale);
5822 }
5823
5824 if (DxShift)
5825 {
5826 TextTop64 -= Dx[2 * i + 1] << 6;
5827 }
5828
5829 previous = glyph_index;
5830
5831 FT_Done_Glyph((FT_Glyph)realglyph);
5832 }
5833
5834 TextWidth64 = TextLeft64 - RealXStart64;
5835 }
5836
5837 /*
5838 * Process the horizontal alignment and modify XStart accordingly.
5839 */
5840 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
5841 {
5842 RealXStart64 -= TextWidth64 / 2;
5843 }
5844 else if ((pdcattr->lTextAlign & TA_RIGHT) == TA_RIGHT)
5845 {
5846 RealXStart64 -= TextWidth64;
5847 if (((RealXStart64 + TextWidth64 + 32) >> 6) <= Start.x + dc->ptlDCOrig.x)
5848 RealXStart64 += 1 << 6;
5849 }
5850
5851 psurf = dc->dclevel.pSurface;
5852 SurfObj = &psurf->SurfObj ;
5853
5854 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
5855 DC_vUpdateBackgroundBrush(dc) ;
5856
5857 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
5858 DC_vUpdateTextBrush(dc) ;
5859
5860 thickness = 1;
5861 if (face->units_per_EM)
5862 {
5863 thickness = face->underline_thickness *
5864 face->size->metrics.y_ppem / face->units_per_EM;
5865 if (thickness <= 0)
5866 thickness = 1;
5867 }
5868
5869 IntEscapeMatrix(&mat1, lfEscapement);
5870 FT_Matrix_Multiply(&mat1, &mat2);
5871 FT_Set_Transform(face, &mat2, NULL);
5872
5873 // background rectangle
5874 vecs[0].x = 0;
5875 vecs[0].y = (DY1 - FontGDI->tmHeight) << 16; // Top Left
5876 vecs[1].x = TextWidth64 << 10;
5877 vecs[1].y = (DY1 - FontGDI->tmHeight) << 16; // Top Right
5878 vecs[2].x = TextWidth64 << 10;
5879 vecs[2].y = DY1 << 16; // Bottom Right
5880 vecs[3].x = 0;
5881 vecs[3].y = DY1 << 16; // Bottom Left
5882
5883 // the starting point
5884 vecs[4].x = 0;
5885 vecs[4].y = (DY1 - FontGDI->tmAscent) << 16;
5886
5887 // underline
5888 if (plf->lfUnderline)
5889 {
5890 int position = 0;
5891 if (face->units_per_EM)
5892 {
5893 position = face->underline_position *
5894 face->size->metrics.y_ppem / face->units_per_EM;
5895 }
5896 vecs[5].x = 0;
5897 vecs[5].y = (DY1 - FontGDI->tmAscent + position) << 16;
5898 vecs[6].x = TextWidth64 << 10;
5899 vecs[6].y = (DY1 - FontGDI->tmAscent + position) << 16;
5900 }
5901
5902 // strike through
5903 if (plf->lfStrikeOut)
5904 {
5905 vecs[7].x = 0;
5906 vecs[7].y = (DY1 - FontGDI->tmAscent + (FontGDI->tmAscent / 3)) << 16;
5907 vecs[8].x = TextWidth64 << 10;
5908 vecs[8].y = (DY1 - FontGDI->tmAscent + (FontGDI->tmAscent / 3)) << 16;
5909 }
5910
5911 // convert vecs to pts
5912 for (i = 0; i < 9; ++i)
5913 {
5914 FT_Vector_Transform(&vecs[i], &mat1);
5915 pts[i].x = (RealXStart64 >> 6) + (vecs[i].x >> 16);
5916 pts[i].y = YStart - (vecs[i].y >> 16);
5917 }
5918
5919 if (fuOptions & ETO_OPAQUE)
5920 {
5921 /* Draw background */
5922 RECTL Rect;
5923 INT X1 = ((RealXStart64 + 32) >> 6);
5924
5925 switch (lfEscapement)
5926 {
5927 case 0:
5928 Rect.left = X1;
5929 Rect.top = ((TextTop64 + 32) >> 6) - DY1;
5930 Rect.right = (RealXStart64 + TextWidth64 + 32) >> 6;
5931 Rect.bottom = ((TextTop64 + 32) >> 6) + DY2;
5932 break;
5933 case 90 * 10:
5934 Rect.left = X1 - DY1;
5935 Rect.top = ((TextTop64 - TextWidth64 + 32) >> 6);
5936 Rect.right = X1 + DY2;
5937 Rect.bottom = ((TextTop64 + 32) >> 6);
5938 break;
5939 case 180 * 10:
5940 Rect.left = (RealXStart64 - TextWidth64 + 32) >> 6;
5941 Rect.top = ((TextTop64 + 32) >> 6) - DY2;
5942 Rect.right = X1;
5943 Rect.bottom = ((TextTop64 + 32) >> 6) + DY1;
5944 break;
5945 case 270 * 10:
5946 Rect.left = X1 - DY2;
5947 Rect.top = ((TextTop64 + 32) >> 6);
5948 Rect.right = X1 + DY1;
5949 Rect.bottom = ((TextTop64 + TextWidth64 + 32) >> 6);
5950 break;
5951 default:
5952 DPRINT1("FIXME: Not implemented lfEscapement\n");
5953 RtlZeroMemory(&Rect, sizeof(Rect));
5954 // FIXME: Use pts[0] ... pts[3] and EngFillPath
5955 }
5956
5957 if (dc->fs & (DC_ACCUM_APP | DC_ACCUM_WMGR))
5958 {
5959 IntUpdateBoundsRect(dc, &Rect);
5960 }
5961
5962 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5963 DC_vUpdateBackgroundBrush(dc);
5964 if (dc->dctype == DCTYPE_DIRECT)
5965 MouseSafetyOnDrawStart(dc->ppdev, Rect.left, Rect.top, Rect.right, Rect.bottom);
5966
5967 SourcePoint.x = SourcePoint.y = 0;
5968 BrushOrigin.x = BrushOrigin.y = 0;
5969
5970 psurf = dc->dclevel.pSurface;
5971 IntEngBitBlt(
5972 &psurf->SurfObj,
5973 NULL,
5974 NULL,
5975 (CLIPOBJ *)&dc->co,
5976 NULL,
5977 &Rect,
5978 &SourcePoint,
5979 &SourcePoint,
5980 &dc->eboBackground.BrushObject,
5981 &BrushOrigin,
5982 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5983
5984 if (dc->dctype == DCTYPE_DIRECT)
5985 MouseSafetyOnDrawEnd(dc->ppdev);
5986 }
5987
5988 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
5989 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
5990
5991 /*
5992 * The main rendering loop.
5993 */
5994 bResult = TRUE;
5995 TextLeft64 = pts[4].x << 6;
5996 TextTop64 = pts[4].y << 6;
5997 previous = 0;
5998 for (i = 0; i < Count; ++i)
5999 {
6000 glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions);
6001 realglyph = NULL;
6002 if (!EmuBold && !EmuItalic && !lfEscapement)
6003 {
6004 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
6005 RenderMode, pmxWorldToDevice);
6006 }
6007 if (!realglyph)
6008 {
6009 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6010 if (error)
6011 {
6012 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
6013 bResult = FALSE;
6014 break;
6015 }
6016
6017 glyph = face->glyph;
6018 if (EmuBold || EmuItalic || lfEscapement)
6019 {
6020 if (EmuBold)
6021 FT_GlyphSlot_Embolden(glyph);
6022 if (EmuItalic)
6023 FT_GlyphSlot_Oblique(glyph);
6024 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
6025 }
6026 else
6027 {
6028 realglyph = ftGdiGlyphCacheSet(face,
6029 glyph_index,
6030 plf->lfHeight,
6031 pmxWorldToDevice,
6032 glyph,
6033 RenderMode);
6034 }
6035 if (!realglyph)
6036 {
6037 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
6038 bResult = FALSE;
6039 break;
6040 }
6041 }
6042
6043 /* retrieve kerning distance and move pen position */
6044 if (use_kerning && previous && glyph_index && NULL == Dx)
6045 {
6046 FT_Vector delta;
6047 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
6048 TextLeft64 += delta.x;
6049 }
6050 DPRINT("TextLeft64: %I64d\n", TextLeft64);
6051 DPRINT("TextTop64: %I64d\n", TextTop64);
6052 DPRINT("Advance: %d\n", realglyph->root.advance.x);
6053
6054 DestRect.left = ((TextLeft64 + 32) >> 6) + realglyph->left;
6055 DestRect.right = DestRect.left + realglyph->bitmap.width;
6056 DestRect.top = ((TextTop64 + 32) >> 6) - realglyph->top;
6057 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
6058
6059 bitSize.cx = realglyph->bitmap.width;
6060 bitSize.cy = realglyph->bitmap.rows;
6061 MaskRect.right = realglyph->bitmap.width;
6062 MaskRect.bottom = realglyph->bitmap.rows;
6063
6064 /* Check if the bitmap has any pixels */
6065 if ((bitSize.cx != 0) && (bitSize.cy != 0))
6066 {
6067 /*
6068 * We should create the bitmap out of the loop at the biggest possible
6069 * glyph size. Then use memset with 0 to clear it and sourcerect to
6070 * limit the work of the transbitblt.
6071 */
6072 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
6073 BMF_8BPP, BMF_TOPDOWN,
6074 realglyph->bitmap.buffer);
6075 if ( !HSourceGlyph )
6076 {
6077 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
6078 bResult = FALSE;
6079 if (EmuBold || EmuItalic)
6080 {
6081 FT_Done_Glyph((FT_Glyph)realglyph);
6082 }
6083
6084 break;
6085 }
6086 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
6087 if ( !SourceGlyphSurf )
6088 {
6089 EngDeleteSurface((HSURF)HSourceGlyph);
6090 DPRINT1("WARNING: EngLockSurface() failed!\n");
6091 bResult = FALSE;
6092 if (EmuBold || EmuItalic)
6093 {
6094 FT_Done_Glyph((FT_Glyph)realglyph);
6095 }
6096
6097 break;
6098 }
6099
6100 /*
6101 * Use the font data as a mask to paint onto the DCs surface using a
6102 * brush.
6103 */
6104 if (lprc && (fuOptions & ETO_CLIPPED) &&
6105 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
6106 {
6107 // We do the check '>=' instead of '>' to possibly save an iteration
6108 // through this loop, since it's breaking after the drawing is done,
6109 // and x is always incremented.
6110 DestRect.right = lprc->right + dc->ptlDCOrig.x;
6111 DoBreak = TRUE;
6112 }
6113 if (lprc && (fuOptions & ETO_CLIPPED) &&
6114 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
6115 {
6116 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
6117 }
6118
6119 if (dc->dctype == DCTYPE_DIRECT)
6120 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
6121
6122 if (!IntEngMaskBlt(
6123 SurfObj,
6124 SourceGlyphSurf,
6125 (CLIPOBJ *)&dc->co,
6126 &exloRGB2Dst.xlo,
6127 &exloDst2RGB.xlo,
6128 &DestRect,
6129 (PPOINTL)&MaskRect,
6130 &dc->eboText.BrushObject,
6131 &BrushOrigin))
6132 {
6133 DPRINT1("Failed to MaskBlt a glyph!\n");
6134 }
6135
6136 if (dc->dctype == DCTYPE_DIRECT)
6137 MouseSafetyOnDrawEnd(dc->ppdev) ;
6138
6139 EngUnlockSurface(SourceGlyphSurf);
6140 EngDeleteSurface((HSURF)HSourceGlyph);
6141 }
6142
6143 if (DoBreak)
6144 {
6145 if (EmuBold || EmuItalic)
6146 {
6147 FT_Done_Glyph((FT_Glyph)realglyph);
6148 }
6149
6150 break;
6151 }
6152
6153 if (NULL == Dx)
6154 {
6155 TextLeft64 += realglyph->root.advance.x >> 10;
6156 TextTop64 -= realglyph->root.advance.y >> 10;
6157 DPRINT("New TextLeft64: %I64d\n", TextLeft64);
6158 }
6159 else
6160 {
6161 // FIXME this should probably be a matrix transform with TextTop64 as well.
6162 Scale = pdcattr->mxWorldToDevice.efM11;
6163 if (FLOATOBJ_Equal0(&Scale))
6164 FLOATOBJ_Set1(&Scale);
6165
6166 /* do the shift before multiplying to preserve precision */
6167 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
6168 TextLeft64 += FLOATOBJ_GetLong(&Scale);
6169 DPRINT("New TextLeft64 2: %I64d\n", TextLeft64);
6170 }
6171
6172 if (DxShift)
6173 {
6174 TextTop64 -= Dx[2 * i + 1] << 6;
6175 }
6176
6177 previous = glyph_index;
6178
6179 /* No cache, so clean up */
6180 if (EmuBold || EmuItalic || lfEscapement)
6181 {
6182 FT_Done_Glyph((FT_Glyph)realglyph);
6183 }
6184 }
6185
6186 if (plf->lfUnderline || plf->lfStrikeOut)
6187 {
6188 INT x0, y0, x1, y1;
6189 if (pts[0].x < pts[2].x)
6190 {
6191 x0 = pts[0].x;
6192 x1 = pts[2].x;
6193 }
6194 else
6195 {
6196 x0 = pts[2].x;
6197 x1 = pts[0].x;
6198 }
6199 if (pts[0].y < pts[2].y)
6200 {
6201 y0 = pts[0].y;
6202 y1 = pts[2].y;
6203 }
6204 else
6205 {
6206 y0 = pts[2].y;
6207 y1 = pts[0].y;
6208 }
6209 if (dc->dctype == DCTYPE_DIRECT)
6210 MouseSafetyOnDrawStart(dc->ppdev, x0, y0, x1, y1);
6211 }
6212
6213 if (plf->lfUnderline)
6214 {
6215 INT i, nEscape = lfEscapement % (180 * 10);
6216 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
6217 {
6218 if (nEscape < 45 * 10 || nEscape > (180 - 45) * 10)
6219 {
6220 // move vertical
6221 EngLineTo(SurfObj, (CLIPOBJ *)&dc->co,
6222 &dc->eboText.BrushObject,
6223 pts[5].x, pts[5].y + i,
6224 pts[6].x, pts[6].y + i,
6225 NULL, ROP2_TO_MIX(R2_COPYPEN));
6226 }
6227 else
6228 {
6229 // move horizontal
6230 EngLineTo(SurfObj, (CLIPOBJ *)&dc->co,
6231 &dc->eboText.BrushObject,
6232 pts[5].x + i, pts[5].y,
6233 pts[6].x + i, pts[6].y,
6234 NULL, ROP2_TO_MIX(R2_COPYPEN));
6235 }
6236 }
6237 }
6238
6239 if (plf->lfStrikeOut)
6240 {
6241 INT i, nEscape = lfEscapement % (180 * 10);
6242 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
6243 {
6244 if (nEscape < 45 * 10 || nEscape > (180 - 45) * 10)
6245 {
6246 // move vertical
6247 EngLineTo(SurfObj, (CLIPOBJ *)&dc->co,
6248 &dc->eboText.BrushObject,
6249 pts[7].x, pts[7].y + i,
6250 pts[8].x, pts[8].y + i,
6251 NULL, ROP2_TO_MIX(R2_COPYPEN));
6252 }
6253 else
6254 {
6255 // move horizontal
6256 EngLineTo(SurfObj, (CLIPOBJ *)&dc->co,
6257 &dc->eboText.BrushObject,
6258 pts[7].x + i, pts[7].y,
6259 pts[8].x + i, pts[8].y,
6260 NULL,
6261 ROP2_TO_MIX(R2_COPYPEN));
6262 }
6263 }
6264 }
6265
6266 if (plf->lfUnderline || plf->lfStrikeOut)
6267 {
6268 if (dc->dctype == DCTYPE_DIRECT)
6269 MouseSafetyOnDrawEnd(dc->ppdev);
6270 }
6271
6272 if (pdcattr->lTextAlign & TA_UPDATECP) {
6273 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
6274 }
6275
6276 IntUnLockFreeType();
6277
6278 EXLATEOBJ_vCleanup(&exloRGB2Dst);
6279 EXLATEOBJ_vCleanup(&exloDst2RGB);
6280
6281 Cleanup:
6282
6283 DC_vFinishBlit(dc, NULL);
6284
6285 if (TextObj != NULL)
6286 TEXTOBJ_UnlockText(TextObj);
6287
6288 DC_UnlockDc(dc);
6289
6290 return bResult;
6291 }
6292
6293 #define STACK_TEXT_BUFFER_SIZE 100
6294 BOOL
6295 APIENTRY
6296 NtGdiExtTextOutW(
6297 IN HDC hDC,
6298 IN INT XStart,
6299 IN INT YStart,
6300 IN UINT fuOptions,
6301 IN OPTIONAL LPRECT UnsafeRect,
6302 IN LPWSTR UnsafeString,
6303 IN INT Count,
6304 IN OPTIONAL LPINT UnsafeDx,
6305 IN DWORD dwCodePage)
6306 {
6307 BOOL Result = FALSE;
6308 NTSTATUS Status = STATUS_SUCCESS;
6309 RECTL SafeRect;
6310 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
6311 PVOID Buffer = LocalBuffer;
6312 LPCWSTR SafeString = NULL;
6313 LPINT SafeDx = NULL;
6314 ULONG BufSize, StringSize, DxSize = 0;
6315
6316 /* Check if String is valid */
6317 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
6318 {
6319 EngSetLastError(ERROR_INVALID_PARAMETER);
6320 return FALSE;
6321 }
6322
6323 if (Count > 0)
6324 {
6325 /* Calculate buffer size for string and Dx values */
6326 BufSize = StringSize = Count * sizeof(WCHAR);
6327 if (UnsafeDx)
6328 {
6329 /* If ETO_PDY is specified, we have pairs of INTs */
6330 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
6331 BufSize += DxSize;
6332 }
6333
6334 /* Check if our local buffer is large enough */
6335 if (BufSize > STACK_TEXT_BUFFER_SIZE)
6336 {
6337 /* It's not, allocate a temp buffer */
6338 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
6339 if (!Buffer)
6340 {
6341 return FALSE;
6342 }
6343 }
6344
6345 /* Probe and copy user mode data to the buffer */
6346 _SEH2_TRY
6347 {
6348 /* Put the Dx before the String to assure alignment of 4 */
6349 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
6350
6351 /* Probe and copy the string */
6352 ProbeForRead(UnsafeString, StringSize, 1);
6353 memcpy((PVOID)SafeString, UnsafeString, StringSize);
6354
6355 /* If we have Dx values... */
6356 if (UnsafeDx)
6357 {
6358 /* ... probe and copy them */
6359 SafeDx = Buffer;
6360 ProbeForRead(UnsafeDx, DxSize, 1);
6361 memcpy(SafeDx, UnsafeDx, DxSize);
6362 }
6363 }
6364 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6365 {
6366 Status = _SEH2_GetExceptionCode();
6367 }
6368 _SEH2_END
6369 if (!NT_SUCCESS(Status))
6370 {
6371 goto cleanup;
6372 }
6373 }
6374
6375 /* If we have a rect, copy it */
6376 if (UnsafeRect)
6377 {
6378 _SEH2_TRY
6379 {
6380 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
6381 SafeRect = *UnsafeRect;
6382 }
6383 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6384 {
6385 Status = _SEH2_GetExceptionCode();
6386 }
6387 _SEH2_END
6388 if (!NT_SUCCESS(Status))
6389 {
6390 goto cleanup;
6391 }
6392 }
6393
6394 /* Finally call the internal routine */
6395 Result = GreExtTextOutW(hDC,
6396 XStart,
6397 YStart,
6398 fuOptions,
6399 &SafeRect,
6400 SafeString,
6401 Count,
6402 SafeDx,
6403 dwCodePage);
6404
6405 cleanup:
6406 /* If we allocated a buffer, free it */
6407 if (Buffer != LocalBuffer)
6408 {
6409 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6410 }
6411
6412 return Result;
6413 }
6414
6415
6416 /*
6417 * @implemented
6418 */
6419 BOOL
6420 APIENTRY
6421 NtGdiGetCharABCWidthsW(
6422 IN HDC hDC,
6423 IN UINT FirstChar,
6424 IN ULONG Count,
6425 IN OPTIONAL PWCHAR UnSafepwch,
6426 IN FLONG fl,
6427 OUT PVOID Buffer)
6428 {
6429 LPABC SafeBuff;
6430 LPABCFLOAT SafeBuffF = NULL;
6431 PDC dc;
6432 PDC_ATTR pdcattr;
6433 PTEXTOBJ TextObj;
6434 PFONTGDI FontGDI;
6435 FT_Face face;
6436 FT_CharMap charmap, found = NULL;
6437 UINT i, glyph_index, BufferSize;
6438 HFONT hFont = 0;
6439 NTSTATUS Status = STATUS_SUCCESS;
6440 PMATRIX pmxWorldToDevice;
6441 PWCHAR Safepwch = NULL;
6442 LOGFONTW *plf;
6443
6444 if (!Buffer)
6445 {
6446 EngSetLastError(ERROR_INVALID_PARAMETER);
6447 return FALSE;
6448 }
6449
6450 if (UnSafepwch)
6451 {
6452 UINT pwchSize = Count * sizeof(WCHAR);
6453 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
6454
6455 if(!Safepwch)
6456 {
6457 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6458 return FALSE;
6459 }
6460
6461 _SEH2_TRY
6462 {
6463 ProbeForRead(UnSafepwch, pwchSize, 1);
6464 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
6465 }
6466 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6467 {
6468 Status = _SEH2_GetExceptionCode();
6469 }
6470 _SEH2_END;
6471 }
6472
6473 if (!NT_SUCCESS(Status))
6474 {
6475 if(Safepwch)
6476 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6477
6478 EngSetLastError(Status);
6479 return FALSE;
6480 }
6481
6482 BufferSize = Count * sizeof(ABC); // Same size!
6483 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6484 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
6485 if (SafeBuff == NULL)
6486 {
6487
6488 if(Safepwch)
6489 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6490
6491 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6492 return FALSE;
6493 }
6494
6495 dc = DC_LockDc(hDC);
6496 if (dc == NULL)
6497 {
6498 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6499
6500 if(Safepwch)
6501 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6502
6503 EngSetLastError(ERROR_INVALID_HANDLE);
6504 return FALSE;
6505 }
6506 pdcattr = dc->pdcattr;
6507 hFont = pdcattr->hlfntNew;
6508 TextObj = RealizeFontInit(hFont);
6509
6510 /* Get the DC's world-to-device transformation matrix */
6511 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6512 DC_UnlockDc(dc);
6513
6514 if (TextObj == NULL)
6515 {
6516 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6517
6518 if(Safepwch)
6519 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6520
6521 EngSetLastError(ERROR_INVALID_HANDLE);
6522 return FALSE;
6523 }
6524
6525 FontGDI = ObjToGDI(TextObj->Font, FONT);
6526
6527 face = FontGDI->SharedFace->Face;
6528 if (face->charmap == NULL)
6529 {
6530 for (i = 0; i < (UINT)face->num_charmaps; i++)
6531 {
6532 charmap = face->charmaps[i];
6533 if (charmap->encoding != 0)
6534 {
6535 found = charmap;
6536 break;
6537 }
6538 }
6539
6540 if (!found)
6541 {
6542 DPRINT1("WARNING: Could not find desired charmap!\n");
6543 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6544
6545 if(Safepwch)
6546 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6547
6548 EngSetLastError(ERROR_INVALID_HANDLE);
6549 return FALSE;
6550 }
6551
6552 IntLockFreeType();
6553 FT_Set_Charmap(face, found);
6554 IntUnLockFreeType();
6555 }
6556
6557 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6558 IntLockFreeType();
6559 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
6560 FtSetCoordinateTransform(face, pmxWorldToDevice);
6561
6562 for (i = FirstChar; i < FirstChar+Count; i++)
6563 {
6564 int adv, lsb, bbx, left, right;
6565
6566 if (Safepwch)
6567 {
6568 glyph_index = get_glyph_index_flagged(face, Safepwch[i - FirstChar], GCABCW_INDICES, fl);
6569 }
6570 else
6571 {
6572 glyph_index = get_glyph_index_flagged(face, i, GCABCW_INDICES, fl);
6573 }
6574 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6575
6576 left = (INT)face->glyph->metrics.horiBearingX & -64;
6577 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
6578 adv = (face->glyph->advance.x + 32) >> 6;
6579
6580 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
6581 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
6582
6583 lsb = left >> 6;
6584 bbx = (right - left) >> 6;
6585 /*
6586 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
6587 */
6588 if (!fl)
6589 {
6590 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
6591 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
6592 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
6593 }
6594 else
6595 {
6596 SafeBuff[i - FirstChar].abcA = lsb;
6597 SafeBuff[i - FirstChar].abcB = bbx;
6598 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
6599 }
6600 }
6601 IntUnLockFreeType();
6602 TEXTOBJ_UnlockText(TextObj);
6603 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6604
6605 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6606
6607 if(Safepwch)
6608 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6609
6610 if (! NT_SUCCESS(Status))
6611 {
6612 SetLastNtError(Status);
6613 return FALSE;
6614 }
6615
6616 DPRINT("NtGdiGetCharABCWidths Worked!\n");
6617 return TRUE;
6618 }
6619
6620 /*
6621 * @implemented
6622 */
6623 BOOL
6624 APIENTRY
6625 NtGdiGetCharWidthW(
6626 IN HDC hDC,
6627 IN UINT FirstChar,
6628 IN UINT Count,
6629 IN OPTIONAL PWCHAR UnSafepwc,
6630 IN FLONG fl,
6631 OUT PVOID Buffer)
6632 {
6633 NTSTATUS Status = STATUS_SUCCESS;
6634 LPINT SafeBuff;
6635 PFLOAT SafeBuffF = NULL;
6636 PDC dc;
6637 PDC_ATTR pdcattr;
6638 PTEXTOBJ TextObj;
6639 PFONTGDI FontGDI;
6640 FT_Face face;
6641 FT_CharMap charmap, found = NULL;
6642 UINT i, glyph_index, BufferSize;
6643 HFONT hFont = 0;
6644 PMATRIX pmxWorldToDevice;
6645 PWCHAR Safepwc = NULL;
6646 LOGFONTW *plf;
6647
6648 if (UnSafepwc)
6649 {
6650 UINT pwcSize = Count * sizeof(WCHAR);
6651 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6652
6653 if(!Safepwc)
6654 {
6655 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6656 return FALSE;
6657 }
6658 _SEH2_TRY
6659 {
6660 ProbeForRead(UnSafepwc, pwcSize, 1);
6661 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6662 }
6663 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6664 {
6665 Status = _SEH2_GetExceptionCode();
6666 }
6667 _SEH2_END;
6668 }
6669
6670 if (!NT_SUCCESS(Status))
6671 {
6672 EngSetLastError(Status);
6673 return FALSE;
6674 }
6675
6676 BufferSize = Count * sizeof(INT); // Same size!
6677 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6678 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
6679 if (SafeBuff == NULL)
6680 {
6681 if(Safepwc)
6682 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6683
6684 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6685 return FALSE;
6686 }
6687
6688 dc = DC_LockDc(hDC);
6689 if (dc == NULL)
6690 {
6691 if(Safepwc)
6692 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6693
6694 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6695 EngSetLastError(ERROR_INVALID_HANDLE);
6696 return FALSE;
6697 }
6698 pdcattr = dc->pdcattr;
6699 hFont = pdcattr->hlfntNew;
6700 TextObj = RealizeFontInit(hFont);
6701 /* Get the DC's world-to-device transformation matrix */
6702 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6703 DC_UnlockDc(dc);
6704
6705 if (TextObj == NULL)
6706 {
6707 if(Safepwc)
6708 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6709
6710 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6711 EngSetLastError(ERROR_INVALID_HANDLE);
6712 return FALSE;
6713 }
6714
6715 FontGDI = ObjToGDI(TextObj->Font, FONT);
6716
6717 face = FontGDI->SharedFace->Face;
6718 if (face->charmap == NULL)
6719 {
6720 for (i = 0; i < (UINT)face->num_charmaps; i++)
6721 {
6722 charmap = face->charmaps[i];
6723 if (charmap->encoding != 0)
6724 {
6725 found = charmap;
6726 break;
6727 }
6728 }
6729
6730 if (!found)
6731 {
6732 DPRINT1("WARNING: Could not find desired charmap!\n");
6733
6734 if(Safepwc)
6735 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6736
6737 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6738 EngSetLastError(ERROR_INVALID_HANDLE);
6739 return FALSE;
6740 }
6741
6742 IntLockFreeType();
6743 FT_Set_Charmap(face, found);
6744 IntUnLockFreeType();
6745 }
6746
6747 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6748 IntLockFreeType();
6749 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
6750 FtSetCoordinateTransform(face, pmxWorldToDevice);
6751
6752 for (i = FirstChar; i < FirstChar+Count; i++)
6753 {
6754 if (Safepwc)
6755 {
6756 glyph_index = get_glyph_index_flagged(face, Safepwc[i - FirstChar], GCW_INDICES, fl);
6757 }
6758 else
6759 {
6760 glyph_index = get_glyph_index_flagged(face, i, GCW_INDICES, fl);
6761 }
6762 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6763 if (!fl)
6764 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
6765 else
6766 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
6767 }
6768 IntUnLockFreeType();
6769 TEXTOBJ_UnlockText(TextObj);
6770 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6771
6772 if(Safepwc)
6773 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6774
6775 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6776 return TRUE;
6777 }
6778
6779
6780 /*
6781 * @implemented
6782 */
6783 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
6784 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
6785 // NOTE: See also GreGetGlyphIndicesW.
6786 __kernel_entry
6787 W32KAPI
6788 DWORD
6789 APIENTRY
6790 NtGdiGetGlyphIndicesW(
6791 _In_ HDC hdc,
6792 _In_reads_opt_(cwc) LPCWSTR pwc,
6793 _In_ INT cwc,
6794 _Out_writes_opt_(cwc) LPWORD pgi,
6795 _In_ DWORD iMode)
6796 {
6797 PDC dc;
6798 PDC_ATTR pdcattr;
6799 PTEXTOBJ TextObj;
6800 PFONTGDI FontGDI;
6801 HFONT hFont = NULL;
6802 NTSTATUS Status = STATUS_SUCCESS;
6803 OUTLINETEXTMETRICW *potm;
6804 INT i;
6805 WCHAR DefChar = 0xffff;
6806 PWSTR Buffer = NULL;
6807 ULONG Size, pwcSize;
6808 PWSTR Safepwc = NULL;
6809 LPCWSTR UnSafepwc = pwc;
6810 LPWORD UnSafepgi = pgi;
6811
6812 /* Check for integer overflow */
6813 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN
6814 return GDI_ERROR;
6815
6816 if (!UnSafepwc && !UnSafepgi)
6817 return cwc;
6818
6819 if (!UnSafepwc || !UnSafepgi)
6820 {
6821 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
6822 return GDI_ERROR;
6823 }
6824
6825 // TODO: Special undocumented case!
6826 if (!pwc && !pgi && (cwc == 0))
6827 {
6828 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n");
6829 return 0;
6830 }
6831
6832 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825
6833 if (cwc == 0)
6834 {
6835 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n");
6836 return GDI_ERROR;
6837 }
6838
6839 dc = DC_LockDc(hdc);
6840 if (!dc)
6841 {
6842 return GDI_ERROR;
6843 }
6844 pdcattr = dc->pdcattr;
6845 hFont = pdcattr->hlfntNew;
6846 TextObj = RealizeFontInit(hFont);
6847 DC_UnlockDc(dc);
6848 if (!TextObj)
6849 {
6850 return GDI_ERROR;
6851 }
6852
6853 FontGDI = ObjToGDI(TextObj->Font, FONT);
6854 TEXTOBJ_UnlockText(TextObj);
6855
6856 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
6857 if (!Buffer)
6858 {
6859 return GDI_ERROR;
6860 }
6861
6862 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
6863 {
6864 DefChar = 0xffff;
6865 }
6866 else
6867 {
6868 FT_Face Face = FontGDI->SharedFace->Face;
6869 if (FT_IS_SFNT(Face))
6870 {
6871 TT_OS2 *pOS2;
6872
6873 IntLockFreeType();
6874 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
6875 DefChar = (pOS2->usDefaultChar ? get_glyph_index(Face, pOS2->usDefaultChar) : 0);
6876 IntUnLockFreeType();
6877 }
6878 else
6879 {
6880 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
6881 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
6882 if (!potm)
6883 {
6884 cwc = GDI_ERROR;
6885 goto ErrorRet;
6886 }
6887 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
6888 if (Size)
6889 DefChar = potm->otmTextMetrics.tmDefaultChar;
6890 ExFreePoolWithTag(potm, GDITAG_TEXT);
6891 }
6892 }
6893
6894 pwcSize = cwc * sizeof(WCHAR);
6895 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6896
6897 if (!Safepwc)
6898 {
6899 Status = STATUS_NO_MEMORY;
6900 goto ErrorRet;
6901 }
6902
6903 _SEH2_TRY
6904 {
6905 ProbeForRead(UnSafepwc, pwcSize, 1);
6906 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6907 }
6908 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6909 {
6910 Status = _SEH2_GetExceptionCode();
6911 }
6912 _SEH2_END;
6913
6914 if (!NT_SUCCESS(Status)) goto ErrorRet;
6915
6916 IntLockFreeType();
6917
6918 for (i = 0; i < cwc; i++)
6919 {
6920 Buffer[i] = get_glyph_index(FontGDI->SharedFace->Face, Safepwc[i]);
6921 if (Buffer[i] == 0)
6922 {
6923 Buffer[i] = DefChar;
6924 }
6925 }
6926
6927 IntUnLockFreeType();
6928
6929 _SEH2_TRY
6930 {
6931 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
6932 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
6933 }
6934 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6935 {
6936 Status = _SEH2_GetExceptionCode();
6937 }
6938 _SEH2_END;
6939
6940 ErrorRet:
6941 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6942 if (Safepwc != NULL)
6943 {
6944 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6945 }
6946 if (NT_SUCCESS(Status)) return cwc;
6947 return GDI_ERROR;
6948 }
6949
6950 /* EOF */