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