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