eef7cb3e5c01bb4448fb81a8d509558cf07c64ba
[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 the angle in tenths of degrees into degrees as a 16.16 fixed-point value */
723 FT_Angle angle = INT_TO_FIXED(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_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3473 FLOAT eM11, widthRatio = 1.0;
3474 FT_Matrix transMat = identityMat;
3475 BOOL needsTransform = FALSE;
3476 INT orientation;
3477 LONG aveWidth;
3478 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3479 OUTLINETEXTMETRICW *potm;
3480 XFORM xForm;
3481 LOGFONTW *plf;
3482
3483 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3484 cjBuf, pvBuf, pmat2);
3485
3486 pdcattr = dc->pdcattr;
3487
3488 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
3489 eM11 = xForm.eM11;
3490
3491 hFont = pdcattr->hlfntNew;
3492 TextObj = RealizeFontInit(hFont);
3493
3494 if (!TextObj)
3495 {
3496 EngSetLastError(ERROR_INVALID_HANDLE);
3497 return GDI_ERROR;
3498 }
3499 FontGDI = ObjToGDI(TextObj->Font, FONT);
3500 ft_face = FontGDI->SharedFace->Face;
3501
3502 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3503 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3504 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3505
3506 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3507 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3508 if (!potm)
3509 {
3510 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3511 TEXTOBJ_UnlockText(TextObj);
3512 return GDI_ERROR;
3513 }
3514 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
3515 if (!Size)
3516 {
3517 /* FIXME: last error? */
3518 ExFreePoolWithTag(potm, GDITAG_TEXT);
3519 TEXTOBJ_UnlockText(TextObj);
3520 return GDI_ERROR;
3521 }
3522
3523 IntLockFreeType();
3524 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3525 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
3526
3527 TEXTOBJ_UnlockText(TextObj);
3528
3529 glyph_index = get_glyph_index_flagged(ft_face, wch, GGO_GLYPH_INDEX, iFormat);
3530 iFormat &= ~GGO_GLYPH_INDEX;
3531
3532 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3533 load_flags |= FT_LOAD_NO_BITMAP;
3534
3535 if (iFormat & GGO_UNHINTED)
3536 {
3537 load_flags |= FT_LOAD_NO_HINTING;
3538 iFormat &= ~GGO_UNHINTED;
3539 }
3540
3541 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3542 if (error)
3543 {
3544 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3545 IntUnLockFreeType();
3546 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3547 return GDI_ERROR;
3548 }
3549 IntUnLockFreeType();
3550
3551 if (aveWidth && potm)
3552 {
3553 widthRatio = (FLOAT)aveWidth * eM11 /
3554 (FLOAT)potm->otmTextMetrics.tmAveCharWidth;
3555 }
3556
3557 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3558 right = (INT)((ft_face->glyph->metrics.horiBearingX +
3559 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3560
3561 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3562 lsb = left >> 6;
3563 bbx = (right - left) >> 6;
3564
3565 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3566
3567 IntLockFreeType();
3568
3569 /* Width scaling transform */
3570 if (widthRatio != 1.0)
3571 {
3572 FT_Matrix scaleMat;
3573 scaleMat.xx = FT_FixedFromFloat(widthRatio);
3574 scaleMat.xy = 0;
3575 scaleMat.yx = 0;
3576 scaleMat.yy = FT_FixedFromFloat(1.0);
3577
3578 FT_Matrix_Multiply(&scaleMat, &transMat);
3579 needsTransform = TRUE;
3580 }
3581
3582 /* World transform */
3583 {
3584 FT_Matrix ftmatrix;
3585 PMATRIX pmx = DC_pmxWorldToDevice(dc);
3586
3587 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3588 FtMatrixFromMx(&ftmatrix, pmx);
3589
3590 if (memcmp(&ftmatrix, &identityMat, sizeof(identityMat)) != 0)
3591 {
3592 FT_Matrix_Multiply(&ftmatrix, &transMat);
3593 needsTransform = TRUE;
3594 }
3595 }
3596
3597 /* Rotation transform */
3598 if (orientation)
3599 {
3600 FT_Matrix rotationMat;
3601 DPRINT("Rotation Trans!\n");
3602 IntEscapeMatrix(&rotationMat, orientation);
3603 FT_Matrix_Multiply(&rotationMat, &transMat);
3604 needsTransform = TRUE;
3605 }
3606
3607 /* Extra transformation specified by caller */
3608 if (pmat2)
3609 {
3610 FT_Matrix extraMat;
3611 DPRINT("MAT2 Matrix Trans!\n");
3612 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
3613 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
3614 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
3615 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
3616 FT_Matrix_Multiply(&extraMat, &transMat);
3617 needsTransform = TRUE;
3618 }
3619
3620 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
3621
3622 if (!needsTransform)
3623 {
3624 DPRINT("No Need to be Transformed!\n");
3625 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3626 bottom = (ft_face->glyph->metrics.horiBearingY -
3627 ft_face->glyph->metrics.height) & -64;
3628 gm.gmCellIncX = adv;
3629 gm.gmCellIncY = 0;
3630 }
3631 else
3632 {
3633 INT xc, yc;
3634 FT_Vector vec;
3635 for (xc = 0; xc < 2; xc++)
3636 {
3637 for (yc = 0; yc < 2; yc++)
3638 {
3639 vec.x = (ft_face->glyph->metrics.horiBearingX +
3640 xc * ft_face->glyph->metrics.width);
3641 vec.y = ft_face->glyph->metrics.horiBearingY -
3642 yc * ft_face->glyph->metrics.height;
3643 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
3644 FT_Vector_Transform(&vec, &transMat);
3645 if (xc == 0 && yc == 0)
3646 {
3647 left = right = vec.x;
3648 top = bottom = vec.y;
3649 }
3650 else
3651 {
3652 if (vec.x < left) left = vec.x;
3653 else if (vec.x > right) right = vec.x;
3654 if (vec.y < bottom) bottom = vec.y;
3655 else if (vec.y > top) top = vec.y;
3656 }
3657 }
3658 }
3659 left = left & -64;
3660 right = (right + 63) & -64;
3661 bottom = bottom & -64;
3662 top = (top + 63) & -64;
3663
3664 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3665 vec.x = ft_face->glyph->metrics.horiAdvance;
3666 vec.y = 0;
3667 FT_Vector_Transform(&vec, &transMat);
3668 gm.gmCellIncX = (vec.x+63) >> 6;
3669 gm.gmCellIncY = -((vec.y+63) >> 6);
3670 }
3671 gm.gmBlackBoxX = (right - left) >> 6;
3672 gm.gmBlackBoxY = (top - bottom) >> 6;
3673 gm.gmptGlyphOrigin.x = left >> 6;
3674 gm.gmptGlyphOrigin.y = top >> 6;
3675
3676 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
3677 gm.gmCellIncX, gm.gmCellIncY,
3678 gm.gmBlackBoxX, gm.gmBlackBoxY,
3679 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
3680
3681 IntUnLockFreeType();
3682
3683
3684 if (iFormat == GGO_METRICS)
3685 {
3686 DPRINT("GGO_METRICS Exit!\n");
3687 *pgm = gm;
3688 return 1; /* FIXME */
3689 }
3690
3691 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
3692 {
3693 DPRINT1("Loaded a bitmap\n");
3694 return GDI_ERROR;
3695 }
3696
3697 switch (iFormat)
3698 {
3699 case GGO_BITMAP:
3700 {
3701 width = gm.gmBlackBoxX;
3702 height = gm.gmBlackBoxY;
3703 pitch = ((width + 31) >> 5) << 2;
3704 needed = pitch * height;
3705
3706 if (!pvBuf || !cjBuf) break;
3707 if (!needed) return GDI_ERROR; /* empty glyph */
3708 if (needed > cjBuf)
3709 return GDI_ERROR;
3710
3711 switch (ft_face->glyph->format)
3712 {
3713 case ft_glyph_format_bitmap:
3714 {
3715 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3716 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
3717 INT h = min( height, ft_face->glyph->bitmap.rows );
3718 while (h--)
3719 {
3720 RtlCopyMemory(dst, src, w);
3721 src += ft_face->glyph->bitmap.pitch;
3722 dst += pitch;
3723 }
3724 break;
3725 }
3726
3727 case ft_glyph_format_outline:
3728 {
3729 ft_bitmap.width = width;
3730 ft_bitmap.rows = height;
3731 ft_bitmap.pitch = pitch;
3732 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
3733 ft_bitmap.buffer = pvBuf;
3734
3735 IntLockFreeType();
3736 if (needsTransform)
3737 {
3738 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3739 }
3740 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3741 /* Note: FreeType will only set 'black' bits for us. */
3742 RtlZeroMemory(pvBuf, needed);
3743 FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
3744 IntUnLockFreeType();
3745 break;
3746 }
3747
3748 default:
3749 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3750 return GDI_ERROR;
3751 }
3752
3753 break;
3754 }
3755
3756 case GGO_GRAY2_BITMAP:
3757 case GGO_GRAY4_BITMAP:
3758 case GGO_GRAY8_BITMAP:
3759 {
3760 unsigned int mult, row, col;
3761 BYTE *start, *ptr;
3762
3763 width = gm.gmBlackBoxX;
3764 height = gm.gmBlackBoxY;
3765 pitch = (width + 3) / 4 * 4;
3766 needed = pitch * height;
3767
3768 if (!pvBuf || !cjBuf) break;
3769 if (!needed) return GDI_ERROR; /* empty glyph */
3770 if (needed > cjBuf)
3771 return GDI_ERROR;
3772
3773 switch (ft_face->glyph->format)
3774 {
3775 case ft_glyph_format_bitmap:
3776 {
3777 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3778 INT h = min( height, ft_face->glyph->bitmap.rows );
3779 INT x;
3780 while (h--)
3781 {
3782 for (x = 0; (UINT)x < pitch; x++)
3783 {
3784 if (x < ft_face->glyph->bitmap.width)
3785 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3786 else
3787 dst[x] = 0;
3788 }
3789 src += ft_face->glyph->bitmap.pitch;
3790 dst += pitch;
3791 }
3792 break;
3793 }
3794 case ft_glyph_format_outline:
3795 {
3796 ft_bitmap.width = width;
3797 ft_bitmap.rows = height;
3798 ft_bitmap.pitch = pitch;
3799 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3800 ft_bitmap.buffer = pvBuf;
3801
3802 IntLockFreeType();
3803 if (needsTransform)
3804 {
3805 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3806 }
3807 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3808 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
3809 FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
3810 IntUnLockFreeType();
3811
3812 if (iFormat == GGO_GRAY2_BITMAP)
3813 mult = 4;
3814 else if (iFormat == GGO_GRAY4_BITMAP)
3815 mult = 16;
3816 else if (iFormat == GGO_GRAY8_BITMAP)
3817 mult = 64;
3818 else
3819 {
3820 return GDI_ERROR;
3821 }
3822
3823 start = pvBuf;
3824 for (row = 0; row < height; row++)
3825 {
3826 ptr = start;
3827 for (col = 0; col < width; col++, ptr++)
3828 {
3829 *ptr = (((int)*ptr) * mult + 128) / 256;
3830 }
3831 start += pitch;
3832 }
3833
3834 break;
3835 }
3836 default:
3837 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3838 return GDI_ERROR;
3839 }
3840
3841 break;
3842 }
3843
3844 case GGO_NATIVE:
3845 {
3846 FT_Outline *outline = &ft_face->glyph->outline;
3847
3848 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
3849
3850 IntLockFreeType();
3851 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
3852
3853 needed = get_native_glyph_outline(outline, cjBuf, NULL);
3854
3855 if (!pvBuf || !cjBuf)
3856 {
3857 IntUnLockFreeType();
3858 break;
3859 }
3860 if (needed > cjBuf)
3861 {
3862 IntUnLockFreeType();
3863 return GDI_ERROR;
3864 }
3865 get_native_glyph_outline(outline, cjBuf, pvBuf);
3866 IntUnLockFreeType();
3867 break;
3868 }
3869
3870 case GGO_BEZIER:
3871 {
3872 FT_Outline *outline = &ft_face->glyph->outline;
3873 if (cjBuf == 0) pvBuf = NULL;
3874
3875 if (needsTransform && pvBuf)
3876 {
3877 IntLockFreeType();
3878 FT_Outline_Transform(outline, &transMat);
3879 IntUnLockFreeType();
3880 }
3881 needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
3882
3883 if (!pvBuf || !cjBuf)
3884 break;
3885 if (needed > cjBuf)
3886 return GDI_ERROR;
3887
3888 get_bezier_glyph_outline(outline, cjBuf, pvBuf);
3889 break;
3890 }
3891
3892 default:
3893 DPRINT1("Unsupported format %u\n", iFormat);
3894 return GDI_ERROR;
3895 }
3896
3897 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
3898 *pgm = gm;
3899 return needed;
3900 }
3901
3902 BOOL
3903 FASTCALL
3904 TextIntGetTextExtentPoint(PDC dc,
3905 PTEXTOBJ TextObj,
3906 LPCWSTR String,
3907 INT Count,
3908 ULONG MaxExtent,
3909 LPINT Fit,
3910 LPINT Dx,
3911 LPSIZE Size,
3912 FLONG fl)
3913 {
3914 PFONTGDI FontGDI;
3915 FT_Face face;
3916 FT_GlyphSlot glyph;
3917 FT_BitmapGlyph realglyph;
3918 INT error, glyph_index, i, previous;
3919 ULONGLONG TotalWidth64 = 0;
3920 BOOL use_kerning;
3921 FT_Render_Mode RenderMode;
3922 BOOLEAN Render;
3923 PMATRIX pmxWorldToDevice;
3924 LOGFONTW *plf;
3925 BOOL EmuBold, EmuItalic;
3926 LONG ascender, descender;
3927
3928 FontGDI = ObjToGDI(TextObj->Font, FONT);
3929
3930 face = FontGDI->SharedFace->Face;
3931 if (NULL != Fit)
3932 {
3933 *Fit = 0;
3934 }
3935
3936 IntLockFreeType();
3937
3938 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3939
3940 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3941 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
3942 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
3943
3944 Render = IntIsFontRenderingEnabled();
3945 if (Render)
3946 RenderMode = IntGetFontRenderMode(plf);
3947 else
3948 RenderMode = FT_RENDER_MODE_MONO;
3949
3950 /* Get the DC's world-to-device transformation matrix */
3951 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3952 FtSetCoordinateTransform(face, pmxWorldToDevice);
3953
3954 use_kerning = FT_HAS_KERNING(face);
3955 previous = 0;
3956
3957 for (i = 0; i < Count; i++)
3958 {
3959 glyph_index = get_glyph_index_flagged(face, *String, GTEF_INDICES, fl);
3960
3961 if (EmuBold || EmuItalic)
3962 realglyph = NULL;
3963 else
3964 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
3965 RenderMode, pmxWorldToDevice);
3966
3967 if (EmuBold || EmuItalic || !realglyph)
3968 {
3969 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3970 if (error)
3971 {
3972 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
3973 break;
3974 }
3975
3976 glyph = face->glyph;
3977 if (EmuBold || EmuItalic)
3978 {
3979 if (EmuBold)
3980 FT_GlyphSlot_Embolden(glyph);
3981 if (EmuItalic)
3982 FT_GlyphSlot_Oblique(glyph);
3983 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
3984 }
3985 else
3986 {
3987 realglyph = ftGdiGlyphCacheSet(face,
3988 glyph_index,
3989 plf->lfHeight,
3990 pmxWorldToDevice,
3991 glyph,
3992 RenderMode);
3993 }
3994
3995 if (!realglyph)
3996 {
3997 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3998 break;
3999 }
4000 }
4001
4002 /* Retrieve kerning distance */
4003 if (use_kerning && previous && glyph_index)
4004 {
4005 FT_Vector delta;
4006 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
4007 TotalWidth64 += delta.x;
4008 }
4009
4010 TotalWidth64 += realglyph->root.advance.x >> 10;
4011
4012 if (((TotalWidth64 + 32) >> 6) <= MaxExtent && NULL != Fit)
4013 {
4014 *Fit = i + 1;
4015 }
4016 if (NULL != Dx)
4017 {
4018 Dx[i] = (TotalWidth64 + 32) >> 6;
4019 }
4020
4021 /* Bold and italic do not use the cache */
4022 if (EmuBold || EmuItalic)
4023 {
4024 FT_Done_Glyph((FT_Glyph)realglyph);
4025 }
4026
4027 previous = glyph_index;
4028 String++;
4029 }
4030 ASSERT(FontGDI->Magic == FONTGDI_MAGIC);
4031 ascender = FontGDI->tmAscent; /* Units above baseline */
4032 descender = FontGDI->tmDescent; /* Units below baseline */
4033 IntUnLockFreeType();
4034
4035 Size->cx = (TotalWidth64 + 32) >> 6;
4036 Size->cy = ascender + descender;
4037
4038 return TRUE;
4039 }
4040
4041
4042 INT
4043 FASTCALL
4044 ftGdiGetTextCharsetInfo(
4045 PDC Dc,
4046 LPFONTSIGNATURE lpSig,
4047 DWORD dwFlags)
4048 {
4049 PDC_ATTR pdcattr;
4050 UINT Ret = DEFAULT_CHARSET;
4051 INT i;
4052 HFONT hFont;
4053 PTEXTOBJ TextObj;
4054 PFONTGDI FontGdi;
4055 FONTSIGNATURE fs;
4056 TT_OS2 *pOS2;
4057 FT_Face Face;
4058 CHARSETINFO csi;
4059 DWORD cp, fs0;
4060 USHORT usACP, usOEM;
4061
4062 pdcattr = Dc->pdcattr;
4063 hFont = pdcattr->hlfntNew;
4064 TextObj = RealizeFontInit(hFont);
4065
4066 if (!TextObj)
4067 {
4068 EngSetLastError(ERROR_INVALID_HANDLE);
4069 return Ret;
4070 }
4071 FontGdi = ObjToGDI(TextObj->Font, FONT);
4072 Face = FontGdi->SharedFace->Face;
4073 TEXTOBJ_UnlockText(TextObj);
4074
4075 memset(&fs, 0, sizeof(FONTSIGNATURE));
4076 IntLockFreeType();
4077 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4078 if (NULL != pOS2)
4079 {
4080 fs.fsCsb[0] = pOS2->ulCodePageRange1;
4081 fs.fsCsb[1] = pOS2->ulCodePageRange2;
4082 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
4083 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
4084 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
4085 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
4086 if (pOS2->version == 0)
4087 {
4088 FT_UInt dummy;
4089
4090 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
4091 fs.fsCsb[0] |= FS_LATIN1;
4092 else
4093 fs.fsCsb[0] |= FS_SYMBOL;
4094 }
4095 }
4096 pOS2 = NULL;
4097 IntUnLockFreeType();
4098 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
4099 if (fs.fsCsb[0] == 0)
4100 { /* Let's see if we can find any interesting cmaps */
4101 for (i = 0; i < Face->num_charmaps; i++)
4102 {
4103 switch (Face->charmaps[i]->encoding)
4104 {
4105 case FT_ENCODING_UNICODE:
4106 case FT_ENCODING_APPLE_ROMAN:
4107 fs.fsCsb[0] |= FS_LATIN1;
4108 break;
4109 case FT_ENCODING_MS_SYMBOL:
4110 fs.fsCsb[0] |= FS_SYMBOL;
4111 break;
4112 default:
4113 break;
4114 }
4115 }
4116 }
4117 if (lpSig)
4118 {
4119 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
4120 }
4121
4122 RtlGetDefaultCodePage(&usACP, &usOEM);
4123 cp = usACP;
4124
4125 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
4126 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
4127 {
4128 DPRINT("Hit 1\n");
4129 Ret = csi.ciCharset;
4130 goto Exit;
4131 }
4132
4133 for (i = 0; i < MAXTCIINDEX; i++)
4134 {
4135 fs0 = 1L << i;
4136 if (fs.fsCsb[0] & fs0)
4137 {
4138 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
4139 {
4140 // *cp = csi.ciACP;
4141 DPRINT("Hit 2\n");
4142 Ret = csi.ciCharset;
4143 goto Exit;
4144 }
4145 else
4146 DPRINT1("TCI failing on %x\n", fs0);
4147 }
4148 }
4149 Exit:
4150 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
4151 return (MAKELONG(csi.ciACP, csi.ciCharset));
4152 }
4153
4154
4155 DWORD
4156 FASTCALL
4157 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
4158 {
4159 DWORD size = 0;
4160 DWORD num_ranges = 0;
4161 FT_Face face = Font->SharedFace->Face;
4162
4163 if (face->charmap->encoding == FT_ENCODING_UNICODE)
4164 {
4165 FT_UInt glyph_code = 0;
4166 FT_ULong char_code, char_code_prev;
4167
4168 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
4169
4170 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
4171 face->num_glyphs, glyph_code, char_code);
4172
4173 if (!glyph_code) return 0;
4174
4175 if (glyphset)
4176 {
4177 glyphset->ranges[0].wcLow = (USHORT)char_code;
4178 glyphset->ranges[0].cGlyphs = 0;
4179 glyphset->cGlyphsSupported = 0;
4180 }
4181
4182 num_ranges = 1;
4183 while (glyph_code)
4184 {
4185 if (char_code < char_code_prev)
4186 {
4187 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
4188 return 0;
4189 }
4190 if (char_code - char_code_prev > 1)
4191 {
4192 num_ranges++;
4193 if (glyphset)
4194 {
4195 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
4196 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
4197 glyphset->cGlyphsSupported++;
4198 }
4199 }
4200 else if (glyphset)
4201 {
4202 glyphset->ranges[num_ranges - 1].cGlyphs++;
4203 glyphset->cGlyphsSupported++;
4204 }
4205 char_code_prev = char_code;
4206 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
4207 }
4208 }
4209 else
4210 DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
4211
4212 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
4213 if (glyphset)
4214 {
4215 glyphset->cbThis = size;
4216 glyphset->cRanges = num_ranges;
4217 glyphset->flAccel = 0;
4218 }
4219 return size;
4220 }
4221
4222
4223 BOOL
4224 FASTCALL
4225 ftGdiGetTextMetricsW(
4226 HDC hDC,
4227 PTMW_INTERNAL ptmwi)
4228 {
4229 PDC dc;
4230 PDC_ATTR pdcattr;
4231 PTEXTOBJ TextObj;
4232 PFONTGDI FontGDI;
4233 FT_Face Face;
4234 TT_OS2 *pOS2;
4235 TT_HoriHeader *pHori;
4236 FT_WinFNT_HeaderRec Win;
4237 ULONG Error;
4238 NTSTATUS Status = STATUS_SUCCESS;
4239 LOGFONTW *plf;
4240
4241 if (!ptmwi)
4242 {
4243 EngSetLastError(STATUS_INVALID_PARAMETER);
4244 return FALSE;
4245 }
4246
4247 if (!(dc = DC_LockDc(hDC)))
4248 {
4249 EngSetLastError(ERROR_INVALID_HANDLE);
4250 return FALSE;
4251 }
4252 pdcattr = dc->pdcattr;
4253 TextObj = RealizeFontInit(pdcattr->hlfntNew);
4254 if (NULL != TextObj)
4255 {
4256 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4257 FontGDI = ObjToGDI(TextObj->Font, FONT);
4258
4259 Face = FontGDI->SharedFace->Face;
4260
4261 IntLockFreeType();
4262 Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
4263 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
4264 IntUnLockFreeType();
4265
4266 if (0 != Error)
4267 {
4268 DPRINT1("Error in setting pixel sizes: %u\n", Error);
4269 Status = STATUS_UNSUCCESSFUL;
4270 }
4271 else
4272 {
4273 FT_Face Face = FontGDI->SharedFace->Face;
4274 Status = STATUS_SUCCESS;
4275
4276 IntLockFreeType();
4277 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
4278 if (NULL == pOS2)
4279 {
4280 DPRINT1("Can't find OS/2 table - not TT font?\n");
4281 Status = STATUS_INTERNAL_ERROR;
4282 }
4283
4284 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
4285 if (NULL == pHori)
4286 {
4287 DPRINT1("Can't find HHEA table - not TT font?\n");
4288 Status = STATUS_INTERNAL_ERROR;
4289 }
4290
4291 Error = FT_Get_WinFNT_Header(Face, &Win);
4292
4293 if (NT_SUCCESS(Status))
4294 {
4295 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
4296
4297 /* FIXME: Fill Diff member */
4298 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
4299 }
4300
4301 IntUnLockFreeType();
4302 }
4303 TEXTOBJ_UnlockText(TextObj);
4304 }
4305 else
4306 {
4307 Status = STATUS_INVALID_HANDLE;
4308 }
4309 DC_UnlockDc(dc);
4310
4311 if (!NT_SUCCESS(Status))
4312 {
4313 SetLastNtError(Status);
4314 return FALSE;
4315 }
4316 return TRUE;
4317 }
4318
4319 DWORD
4320 FASTCALL
4321 ftGdiGetFontData(
4322 PFONTGDI FontGdi,
4323 DWORD Table,
4324 DWORD Offset,
4325 PVOID Buffer,
4326 DWORD Size)
4327 {
4328 DWORD Result = GDI_ERROR;
4329 FT_Face Face = FontGdi->SharedFace->Face;
4330
4331 IntLockFreeType();
4332
4333 if (FT_IS_SFNT(Face))
4334 {
4335 if (Table)
4336 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
4337 (Table << 8 & 0xFF0000);
4338
4339 if (!Buffer) Size = 0;
4340
4341 if (Buffer && Size)
4342 {
4343 FT_Error Error;
4344 FT_ULong Needed = 0;
4345
4346 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
4347
4348 if ( !Error && Needed < Size) Size = Needed;
4349 }
4350 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
4351 Result = Size;
4352 }
4353
4354 IntUnLockFreeType();
4355
4356 return Result;
4357 }
4358
4359 #define GOT_PENALTY(name, value) Penalty += (value)
4360
4361 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
4362 static UINT
4363 GetFontPenalty(const LOGFONTW * LogFont,
4364 const OUTLINETEXTMETRICW * Otm,
4365 const char * style_name)
4366 {
4367 ULONG Penalty = 0;
4368 BYTE Byte;
4369 LONG Long;
4370 BOOL fNeedScaling = FALSE;
4371 const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
4372 const TEXTMETRICW * TM = &Otm->otmTextMetrics;
4373 WCHAR* ActualNameW;
4374
4375 ASSERT(Otm);
4376 ASSERT(LogFont);
4377
4378 /* FIXME: IntSizeSynth Penalty 20 */
4379 /* FIXME: SmallPenalty Penalty 1 */
4380 /* FIXME: FaceNameSubst Penalty 500 */
4381
4382 Byte = LogFont->lfCharSet;
4383 if (Byte == DEFAULT_CHARSET)
4384 {
4385 if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0)
4386 {
4387 if (Byte == ANSI_CHARSET)
4388 {
4389 DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
4390 }
4391 /* We assume SYMBOL_CHARSET for "Marlett" font */
4392 Byte = SYMBOL_CHARSET;
4393 }
4394 }
4395
4396 if (Byte != TM->tmCharSet)
4397 {
4398 if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
4399 {
4400 /* CharSet Penalty 65000 */
4401 /* Requested charset does not match the candidate's. */
4402 GOT_PENALTY("CharSet", 65000);
4403 }
4404 else
4405 {
4406 if (UserCharSet != TM->tmCharSet)
4407 {
4408 /* UNDOCUMENTED: Not user language */
4409 GOT_PENALTY("UNDOCUMENTED:NotUserLanguage", 100);
4410
4411 if (ANSI_CHARSET != TM->tmCharSet)
4412 {
4413 /* UNDOCUMENTED: Not ANSI charset */
4414 GOT_PENALTY("UNDOCUMENTED:NotAnsiCharSet", 100);
4415 }
4416 }
4417 }
4418 }
4419
4420 Byte = LogFont->lfOutPrecision;
4421 switch (Byte)
4422 {
4423 case OUT_DEFAULT_PRECIS:
4424 /* nothing to do */
4425 break;
4426 case OUT_DEVICE_PRECIS:
4427 if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
4428 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
4429 {
4430 /* OutputPrecision Penalty 19000 */
4431 /* Requested OUT_STROKE_PRECIS, but the device can't do it
4432 or the candidate is not a vector font. */
4433 GOT_PENALTY("OutputPrecision", 19000);
4434 }
4435 break;
4436 default:
4437 if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
4438 {
4439 /* OutputPrecision Penalty 19000 */
4440 /* Or OUT_STROKE_PRECIS not requested, and the candidate
4441 is a vector font that requires GDI support. */
4442 GOT_PENALTY("OutputPrecision", 19000);
4443 }
4444 break;
4445 }
4446
4447 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4448 if (Byte == DEFAULT_PITCH)
4449 Byte = VARIABLE_PITCH;
4450 if (Byte == FIXED_PITCH)
4451 {
4452 if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
4453 {
4454 /* FixedPitch Penalty 15000 */
4455 /* Requested a fixed pitch font, but the candidate is a
4456 variable pitch font. */
4457 GOT_PENALTY("FixedPitch", 15000);
4458 }
4459 }
4460 if (Byte == VARIABLE_PITCH)
4461 {
4462 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4463 {
4464 /* PitchVariable Penalty 350 */
4465 /* Requested a variable pitch font, but the candidate is not a
4466 variable pitch font. */
4467 GOT_PENALTY("PitchVariable", 350);
4468 }
4469 }
4470
4471 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4472 if (Byte == DEFAULT_PITCH)
4473 {
4474 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4475 {
4476 /* DefaultPitchFixed Penalty 1 */
4477 /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
4478 GOT_PENALTY("DefaultPitchFixed", 1);
4479 }
4480 }
4481
4482 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
4483
4484 if (LogFont->lfFaceName[0] != UNICODE_NULL)
4485 {
4486 BOOL Found = FALSE;
4487
4488 /* localized family name */
4489 if (!Found)
4490 {
4491 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4492 }
4493 /* localized full name */
4494 if (!Found)
4495 {
4496 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
4497 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4498 }
4499 if (!Found)
4500 {
4501 /* FaceName Penalty 10000 */
4502 /* Requested a face name, but the candidate's face name
4503 does not match. */
4504 GOT_PENALTY("FaceName", 10000);
4505 }
4506 }
4507
4508 Byte = (LogFont->lfPitchAndFamily & 0xF0);
4509 if (Byte != FF_DONTCARE)
4510 {
4511 if (Byte != (TM->tmPitchAndFamily & 0xF0))
4512 {
4513 /* Family Penalty 9000 */
4514 /* Requested a family, but the candidate's family is different. */
4515 GOT_PENALTY("Family", 9000);
4516 }
4517 }
4518
4519 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
4520 {
4521 /* FamilyUnknown Penalty 8000 */
4522 /* Requested a family, but the candidate has no family. */
4523 GOT_PENALTY("FamilyUnknown", 8000);
4524 }
4525
4526 /* Is the candidate a non-vector font? */
4527 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4528 {
4529 /* Is lfHeight specified? */
4530 if (LogFont->lfHeight != 0)
4531 {
4532 if (labs(LogFont->lfHeight) < TM->tmHeight)
4533 {
4534 /* HeightBigger Penalty 600 */
4535 /* The candidate is a nonvector font and is bigger than the
4536 requested height. */
4537 GOT_PENALTY("HeightBigger", 600);
4538 /* HeightBiggerDifference Penalty 150 */
4539 /* The candidate is a raster font and is larger than the
4540 requested height. Penalty * height difference */
4541 GOT_PENALTY("HeightBiggerDifference", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)));
4542
4543 fNeedScaling = TRUE;
4544 }
4545 if (TM->tmHeight < labs(LogFont->lfHeight))
4546 {
4547 /* HeightSmaller Penalty 150 */
4548 /* The candidate is a raster font and is smaller than the
4549 requested height. Penalty * height difference */
4550 GOT_PENALTY("HeightSmaller", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)));
4551
4552 fNeedScaling = TRUE;
4553 }
4554 }
4555 }
4556
4557 switch (LogFont->lfPitchAndFamily & 0xF0)
4558 {
4559 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4560 switch (TM->tmPitchAndFamily & 0xF0)
4561 {
4562 case FF_DECORATIVE: case FF_SCRIPT:
4563 /* FamilyUnlikely Penalty 50 */
4564 /* Requested a roman/modern/swiss family, but the
4565 candidate is decorative/script. */
4566 GOT_PENALTY("FamilyUnlikely", 50);
4567 break;
4568 default:
4569 break;
4570 }
4571 break;
4572 case FF_DECORATIVE: case FF_SCRIPT:
4573 switch (TM->tmPitchAndFamily & 0xF0)
4574 {
4575 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4576 /* FamilyUnlikely Penalty 50 */
4577 /* Or requested decorative/script, and the candidate is
4578 roman/modern/swiss. */
4579 GOT_PENALTY("FamilyUnlikely", 50);
4580 break;
4581 default:
4582 break;
4583 }
4584 default:
4585 break;
4586 }
4587
4588 if (LogFont->lfWidth != 0)
4589 {
4590 if (LogFont->lfWidth != TM->tmAveCharWidth)
4591 {
4592 /* Width Penalty 50 */
4593 /* Requested a nonzero width, but the candidate's width
4594 doesn't match. Penalty * width difference */
4595 GOT_PENALTY("Width", 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth));
4596
4597 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4598 fNeedScaling = TRUE;
4599 }
4600 }
4601
4602 if (fNeedScaling)
4603 {
4604 /* SizeSynth Penalty 50 */
4605 /* The candidate is a raster font that needs scaling by GDI. */
4606 GOT_PENALTY("SizeSynth", 50);
4607 }
4608
4609 if (!!LogFont->lfItalic != !!TM->tmItalic)
4610 {
4611 if (!LogFont->lfItalic && ItalicFromStyle(style_name))
4612 {
4613 /* Italic Penalty 4 */
4614 /* Requested font and candidate font do not agree on italic status,
4615 and the desired result cannot be simulated. */
4616 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
4617 GOT_PENALTY("Italic", 40);
4618 }
4619 else if (LogFont->lfItalic && !ItalicFromStyle(style_name))
4620 {
4621 /* ItalicSim Penalty 1 */
4622 /* Requested italic font but the candidate is not italic,
4623 although italics can be simulated. */
4624 GOT_PENALTY("ItalicSim", 1);
4625 }
4626 }
4627
4628 if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
4629 {
4630 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
4631 {
4632 /* NotTrueType Penalty 4 */
4633 /* Requested OUT_TT_PRECIS, but the candidate is not a
4634 TrueType font. */
4635 GOT_PENALTY("NotTrueType", 4);
4636 }
4637 }
4638
4639 Long = LogFont->lfWeight;
4640 if (LogFont->lfWeight == FW_DONTCARE)
4641 Long = FW_NORMAL;
4642 if (Long != TM->tmWeight)
4643 {
4644 /* Weight Penalty 3 */
4645 /* The candidate's weight does not match the requested weight.
4646 Penalty * (weight difference/10) */
4647 GOT_PENALTY("Weight", 3 * (labs(Long - TM->tmWeight) / 10));
4648 }
4649
4650 if (!LogFont->lfUnderline && TM->tmUnderlined)
4651 {
4652 /* Underline Penalty 3 */
4653 /* Requested font has no underline, but the candidate is
4654 underlined. */
4655 GOT_PENALTY("Underline", 3);
4656 }
4657
4658 if (!LogFont->lfStrikeOut && TM->tmStruckOut)
4659 {
4660 /* StrikeOut Penalty 3 */
4661 /* Requested font has no strike-out, but the candidate is
4662 struck out. */
4663 GOT_PENALTY("StrikeOut", 3);
4664 }
4665
4666 /* Is the candidate a non-vector font? */
4667 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4668 {
4669 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
4670 {
4671 /* VectorHeightSmaller Penalty 2 */
4672 /* Candidate is a vector font that is smaller than the
4673 requested height. Penalty * height difference */
4674 GOT_PENALTY("VectorHeightSmaller", 2 * labs(TM->tmHeight - LogFont->lfHeight));
4675 }
4676 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
4677 {
4678 /* VectorHeightBigger Penalty 1 */
4679 /* Candidate is a vector font that is bigger than the
4680 requested height. Penalty * height difference */
4681 GOT_PENALTY("VectorHeightBigger", 1 * labs(TM->tmHeight - LogFont->lfHeight));
4682 }
4683 }
4684
4685 if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
4686 {
4687 /* DeviceFavor Penalty 2 */
4688 /* Extra penalty for all nondevice fonts. */
4689 GOT_PENALTY("DeviceFavor", 2);
4690 }
4691
4692 if (TM->tmAveCharWidth >= 5 && TM->tmHeight >= 5)
4693 {
4694 if (TM->tmAveCharWidth / TM->tmHeight >= 3)
4695 {
4696 /* Aspect Penalty 30 */
4697 /* The aspect rate is >= 3. It seems like a bad font. */
4698 GOT_PENALTY("Aspect", ((TM->tmAveCharWidth / TM->tmHeight) - 2) * 30);
4699 }
4700 else if (TM->tmHeight / TM->tmAveCharWidth >= 3)
4701 {
4702 /* Aspect Penalty 30 */
4703 /* The aspect rate is >= 3. It seems like a bad font. */
4704 GOT_PENALTY("Aspect", ((TM->tmHeight / TM->tmAveCharWidth) - 2) * 30);
4705 }
4706 }
4707
4708 if (Penalty < 200)
4709 {
4710 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
4711 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
4712 "tmCharSet:%d, tmWeight:%ld\n",
4713 Penalty, LogFont->lfFaceName, ActualNameW,
4714 LogFont->lfCharSet, LogFont->lfWeight,
4715 TM->tmCharSet, TM->tmWeight);
4716 }
4717
4718 return Penalty; /* success */
4719 }
4720
4721 #undef GOT_PENALTY
4722
4723 static __inline VOID
4724 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
4725 const LOGFONTW *LogFont,
4726 const PLIST_ENTRY Head)
4727 {
4728 ULONG Penalty;
4729 PLIST_ENTRY Entry;
4730 PFONT_ENTRY CurrentEntry;
4731 FONTGDI *FontGDI;
4732 OUTLINETEXTMETRICW *Otm = NULL;
4733 UINT OtmSize, OldOtmSize = 0;
4734 FT_Face Face;
4735
4736 ASSERT(FontObj);
4737 ASSERT(MatchPenalty);
4738 ASSERT(LogFont);
4739 ASSERT(Head);
4740
4741 /* Start with a pretty big buffer */
4742 OldOtmSize = 0x200;
4743 Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
4744
4745 /* get the FontObj of lowest penalty */
4746 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
4747 {
4748 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
4749
4750 FontGDI = CurrentEntry->Font;
4751 ASSERT(FontGDI);
4752 Face = FontGDI->SharedFace->Face;
4753
4754 /* get text metrics */
4755 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4756 if (OtmSize > OldOtmSize)
4757 {
4758 if (Otm)
4759 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4760 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
4761 }
4762
4763 /* update FontObj if lowest penalty */
4764 if (Otm)
4765 {
4766 IntLockFreeType();
4767 IntRequestFontSize(NULL, FontGDI, LogFont->lfWidth, LogFont->lfHeight);
4768 IntUnLockFreeType();
4769
4770 OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
4771 if (!OtmSize)
4772 continue;
4773
4774 OldOtmSize = OtmSize;
4775
4776 Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
4777 if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
4778 {
4779 *FontObj = GDIToObj(FontGDI, FONT);
4780 *MatchPenalty = Penalty;
4781 }
4782 }
4783 }
4784
4785 if (Otm)
4786 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4787 }
4788
4789 static
4790 VOID
4791 FASTCALL
4792 IntFontType(PFONTGDI Font)
4793 {
4794 PS_FontInfoRec psfInfo;
4795 FT_ULong tmp_size = 0;
4796 FT_Face Face = Font->SharedFace->Face;
4797
4798 ASSERT_FREETYPE_LOCK_NOT_HELD();
4799 IntLockFreeType();
4800
4801 if (FT_HAS_MULTIPLE_MASTERS(Face))
4802 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
4803 if (FT_HAS_VERTICAL(Face))
4804 Font->FontObj.flFontType |= FO_VERT_FACE;
4805 if (!FT_IS_SCALABLE(Face))
4806 Font->FontObj.flFontType |= FO_TYPE_RASTER;
4807 if (FT_IS_SFNT(Face))
4808 {
4809 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
4810 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
4811 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4812 }
4813 if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
4814 {
4815 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4816 }
4817 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
4818 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
4819 {
4820 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
4821 }
4822
4823 IntUnLockFreeType();
4824 }
4825
4826 static BOOL
4827 MatchFontName(PSHARED_FACE SharedFace, LPCWSTR lfFaceName, FT_UShort NameID, FT_UShort LangID)
4828 {
4829 NTSTATUS Status;
4830 UNICODE_STRING Name1, Name2;
4831
4832 if (lfFaceName[0] == UNICODE_NULL)
4833 return FALSE;
4834
4835 RtlInitUnicodeString(&Name1, lfFaceName);
4836
4837 RtlInitUnicodeString(&Name2, NULL);
4838 Status = IntGetFontLocalizedName(&Name2, SharedFace, NameID, LangID);
4839
4840 if (NT_SUCCESS(Status))
4841 {
4842 if (RtlCompareUnicodeString(&Name1, &Name2, TRUE) == 0)
4843 {
4844 RtlFreeUnicodeString(&Name2);
4845 return TRUE;
4846 }
4847
4848 RtlFreeUnicodeString(&Name2);
4849 }
4850
4851 return FALSE;
4852 }
4853
4854 static BOOL
4855 MatchFontNames(PSHARED_FACE SharedFace, LPCWSTR lfFaceName)
4856 {
4857 if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, LANG_ENGLISH) ||
4858 MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, LANG_ENGLISH))
4859 {
4860 return TRUE;
4861 }
4862 if (PRIMARYLANGID(gusLanguageID) != LANG_ENGLISH)
4863 {
4864 if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, gusLanguageID) ||
4865 MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, gusLanguageID))
4866 {
4867 return TRUE;
4868 }
4869 }
4870 return FALSE;
4871 }
4872
4873 NTSTATUS
4874 FASTCALL
4875 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
4876 {
4877 NTSTATUS Status = STATUS_SUCCESS;
4878 PTEXTOBJ TextObj;
4879 PPROCESSINFO Win32Process;
4880 ULONG MatchPenalty;
4881 LOGFONTW *pLogFont;
4882 LOGFONTW SubstitutedLogFont;
4883 FT_Face Face;
4884
4885 if (!pTextObj)
4886 {
4887 TextObj = TEXTOBJ_LockText(FontHandle);
4888 if (NULL == TextObj)
4889 {
4890 return STATUS_INVALID_HANDLE;
4891 }
4892
4893 if (TextObj->fl & TEXTOBJECT_INIT)
4894 {
4895 TEXTOBJ_UnlockText(TextObj);
4896 return STATUS_SUCCESS;
4897 }
4898 }
4899 else
4900 {
4901 TextObj = pTextObj;
4902 }
4903
4904 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4905
4906 /* substitute */
4907 SubstitutedLogFont = *pLogFont;
4908 DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
4909 SubstituteFontRecurse(&SubstitutedLogFont);
4910 DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
4911
4912 MatchPenalty = 0xFFFFFFFF;
4913 TextObj->Font = NULL;
4914
4915 Win32Process = PsGetCurrentProcessWin32Process();
4916
4917 /* Search private fonts */
4918 IntLockProcessPrivateFonts(Win32Process);
4919 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4920 &Win32Process->PrivateFontListHead);
4921 IntUnLockProcessPrivateFonts(Win32Process);
4922
4923 /* Search system fonts */
4924 IntLockGlobalFonts();
4925 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4926 &g_FontListHead);
4927 IntUnLockGlobalFonts();
4928
4929 if (NULL == TextObj->Font)
4930 {
4931 DPRINT1("Request font %S not found, no fonts loaded at all\n",
4932 pLogFont->lfFaceName);
4933 Status = STATUS_NOT_FOUND;
4934 }
4935 else
4936 {
4937 UNICODE_STRING Name;
4938 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
4939 PSHARED_FACE SharedFace = FontGdi->SharedFace;
4940
4941 IntLockFreeType();
4942 IntRequestFontSize(NULL, FontGdi, pLogFont->lfWidth, pLogFont->lfHeight);
4943 IntUnLockFreeType();
4944
4945 TextObj->TextFace[0] = UNICODE_NULL;
4946 if (MatchFontNames(SharedFace, SubstitutedLogFont.lfFaceName))
4947 {
4948 RtlStringCchCopyW(TextObj->TextFace, _countof(TextObj->TextFace), pLogFont->lfFaceName);
4949 }
4950 else
4951 {
4952 RtlInitUnicodeString(&Name, NULL);
4953 Status = IntGetFontLocalizedName(&Name, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
4954 if (NT_SUCCESS(Status))
4955 {
4956 /* truncated copy */
4957 IntUnicodeStringToBuffer(TextObj->TextFace, sizeof(TextObj->TextFace), &Name);
4958 RtlFreeUnicodeString(&Name);
4959 }
4960 }
4961
4962 // Need hdev, when freetype is loaded need to create DEVOBJ for
4963 // Consumer and Producer.
4964 TextObj->Font->iUniq = 1; // Now it can be cached.
4965 IntFontType(FontGdi);
4966 FontGdi->flType = TextObj->Font->flFontType;
4967 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
4968 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
4969 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
4970 if (pLogFont->lfWeight != FW_DONTCARE)
4971 FontGdi->RequestWeight = pLogFont->lfWeight;
4972 else
4973 FontGdi->RequestWeight = FW_NORMAL;
4974
4975 Face = FontGdi->SharedFace->Face;
4976
4977 //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name);
4978
4979 if (!FontGdi->OriginalItalic)
4980 FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name);
4981
4982 TextObj->fl |= TEXTOBJECT_INIT;
4983 Status = STATUS_SUCCESS;
4984 }
4985
4986 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
4987
4988 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
4989
4990 return Status;
4991 }
4992
4993
4994 static
4995 BOOL
4996 FASTCALL
4997 IntGetFullFileName(
4998 POBJECT_NAME_INFORMATION NameInfo,
4999 ULONG Size,
5000 PUNICODE_STRING FileName)
5001 {
5002 NTSTATUS Status;
5003 OBJECT_ATTRIBUTES ObjectAttributes;
5004 HANDLE hFile;
5005 IO_STATUS_BLOCK IoStatusBlock;
5006 ULONG Desired;
5007
5008 InitializeObjectAttributes(&ObjectAttributes,
5009 FileName,
5010 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
5011 NULL,
5012 NULL);
5013
5014 Status = ZwOpenFile(
5015 &hFile,
5016 0, // FILE_READ_ATTRIBUTES,
5017 &ObjectAttributes,
5018 &IoStatusBlock,
5019 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
5020 0);
5021
5022 if (!NT_SUCCESS(Status))
5023 {
5024 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
5025 return FALSE;
5026 }
5027
5028 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
5029 ZwClose(hFile);
5030 if (!NT_SUCCESS(Status))
5031 {
5032 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
5033 return FALSE;
5034 }
5035
5036 return TRUE;
5037 }
5038
5039 static BOOL
5040 EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2)
5041 {
5042 const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
5043 const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
5044 const LOGFONTW *plf1 = &pLog1->elfLogFont;
5045 const LOGFONTW *plf2 = &pLog2->elfLogFont;
5046
5047 if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0)
5048 {
5049 return FALSE;
5050 }
5051
5052 if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0)
5053 {
5054 return FALSE;
5055 }
5056
5057 return TRUE;
5058 }
5059
5060 static VOID
5061 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
5062 {
5063 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
5064 if (FamInfo->EnumLogFontEx.elfStyle[0] &&
5065 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
5066 {
5067 wcscat(psz, L" ");
5068 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
5069 }
5070 }
5071
5072 BOOL
5073 FASTCALL
5074 IntGdiGetFontResourceInfo(
5075 PUNICODE_STRING FileName,
5076 PVOID pBuffer,
5077 DWORD *pdwBytes,
5078 DWORD dwType)
5079 {
5080 UNICODE_STRING EntryFileName;
5081 POBJECT_NAME_INFORMATION NameInfo1 = NULL, NameInfo2 = NULL;
5082 PLIST_ENTRY ListEntry;
5083 PFONT_ENTRY FontEntry;
5084 ULONG Size, i, Count;
5085 LPBYTE pbBuffer;
5086 BOOL IsEqual;
5087 FONTFAMILYINFO *FamInfo;
5088 const ULONG MaxFamInfo = 64;
5089 const ULONG MAX_FAM_INFO_BYTES = sizeof(FONTFAMILYINFO) * MaxFamInfo;
5090 BOOL bSuccess;
5091 const ULONG NAMEINFO_SIZE = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
5092
5093 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
5094
5095 do
5096 {
5097 /* Create buffer for full path name */
5098 NameInfo1 = ExAllocatePoolWithTag(PagedPool, NAMEINFO_SIZE, TAG_FINF);
5099 if (!NameInfo1)
5100 break;
5101
5102 /* Get the full path name */
5103 if (!IntGetFullFileName(NameInfo1, NAMEINFO_SIZE, FileName))
5104 break;
5105
5106 /* Create a buffer for the entries' names */
5107 NameInfo2 = ExAllocatePoolWithTag(PagedPool, NAMEINFO_SIZE, TAG_FINF);
5108 if (!NameInfo2)
5109 break;
5110
5111 FamInfo = ExAllocatePoolWithTag(PagedPool, MAX_FAM_INFO_BYTES, TAG_FINF);
5112 } while (0);
5113
5114 if (!NameInfo1 || !NameInfo2 || !FamInfo)
5115 {
5116 if (NameInfo2)
5117 ExFreePoolWithTag(NameInfo2, TAG_FINF);
5118
5119 if (NameInfo1)
5120 ExFreePoolWithTag(NameInfo1, TAG_FINF);
5121
5122 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5123 return FALSE;
5124 }
5125
5126 Count = 0;
5127
5128 /* Try to find the pathname in the global font list */
5129 IntLockGlobalFonts();
5130 for (ListEntry = g_FontListHead.Flink; ListEntry != &g_FontListHead;
5131 ListEntry = ListEntry->Flink)
5132 {
5133 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
5134 if (FontEntry->Font->Filename == NULL)
5135 continue;
5136
5137 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
5138 if (!IntGetFullFileName(NameInfo2, NAMEINFO_SIZE, &EntryFileName))
5139 continue;
5140
5141 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
5142 continue;
5143
5144 IsEqual = FALSE;
5145 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
5146 NULL, FontEntry->Font);
5147 for (i = 0; i < Count; ++i)
5148 {
5149 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
5150 {
5151 IsEqual = TRUE;
5152 break;
5153 }
5154 }
5155 if (!IsEqual)
5156 {
5157 /* Found */
5158 ++Count;
5159 if (Count >= MaxFamInfo)
5160 break;
5161 }
5162 }
5163 IntUnLockGlobalFonts();
5164
5165 /* Free the buffers */
5166 ExFreePoolWithTag(NameInfo1, TAG_FINF);
5167 ExFreePoolWithTag(NameInfo2, TAG_FINF);
5168
5169 if (Count == 0 && dwType != 5)
5170 {
5171 /* Font could not be found in system table
5172 dwType == 5 will still handle this */
5173 ExFreePoolWithTag(FamInfo, TAG_FINF);
5174 return FALSE;
5175 }
5176
5177 bSuccess = FALSE;
5178 switch (dwType)
5179 {
5180 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
5181 Size = sizeof(DWORD);
5182 if (*pdwBytes == 0)
5183 {
5184 *pdwBytes = Size;
5185 bSuccess = TRUE;
5186 }
5187 else if (pBuffer)
5188 {
5189 if (*pdwBytes >= Size)
5190 {
5191 *(DWORD*)pBuffer = Count;
5192 }
5193 *pdwBytes = Size;
5194 bSuccess = TRUE;
5195 }
5196 break;
5197
5198 case 1: /* copy the font title */
5199 /* calculate the required size */
5200 Size = 0;
5201 for (i = 0; i < Count; ++i)
5202 {
5203 if (i > 0)
5204 Size += 3; /* " & " */
5205 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
5206 if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
5207 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
5208 {
5209 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
5210 }
5211 }
5212 Size += 2; /* "\0\0" */
5213 Size *= sizeof(WCHAR);
5214
5215 if (*pdwBytes == 0)
5216 {
5217 *pdwBytes = Size;
5218 bSuccess = TRUE;
5219 }
5220 else if (pBuffer)
5221 {
5222 if (*pdwBytes >= Size)
5223 {
5224 /* store font title to buffer */
5225 WCHAR *psz = pBuffer;
5226 *psz = 0;
5227 for (i = 0; i < Count; ++i)
5228 {
5229 if (i > 0)
5230 wcscat(psz, L" & ");
5231 IntAddNameFromFamInfo(psz, &FamInfo[i]);
5232 }
5233 psz[wcslen(psz) + 1] = UNICODE_NULL;
5234 *pdwBytes = Size;
5235 bSuccess = TRUE;
5236 }
5237 else
5238 {
5239 *pdwBytes = 1024; /* this is confirmed value */
5240 }
5241 }
5242 break;
5243
5244 case 2: /* Copy an array of LOGFONTW */
5245 Size = Count * sizeof(LOGFONTW);
5246 if (*pdwBytes == 0)
5247 {
5248 *pdwBytes = Size;
5249 bSuccess = TRUE;
5250 }
5251 else if (pBuffer)
5252 {
5253 if (*pdwBytes >= Size)
5254 {
5255 pbBuffer = (LPBYTE)pBuffer;
5256 for (i = 0; i < Count; ++i)
5257 {
5258 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
5259 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
5260 pbBuffer += sizeof(LOGFONTW);
5261 }
5262 }
5263 *pdwBytes = Size;
5264 bSuccess = TRUE;
5265 }
5266 else
5267 {
5268 *pdwBytes = 1024; /* this is confirmed value */
5269 }
5270 break;
5271
5272 case 3:
5273 Size = sizeof(DWORD);
5274 if (*pdwBytes == 0)
5275 {
5276 *pdwBytes = Size;
5277 bSuccess = TRUE;
5278 }
5279 else if (pBuffer)
5280 {
5281 if (*pdwBytes >= Size)
5282 {
5283 /* FIXME: What exactly is copied here? */
5284 *(DWORD*)pBuffer = 1;
5285 }
5286 *pdwBytes = Size;
5287 bSuccess = TRUE;
5288 }
5289 break;
5290
5291 case 4: /* full file path */
5292 if (FileName->Length >= 4 * sizeof(WCHAR))
5293 {
5294 /* The beginning of FileName is \??\ */
5295 LPWSTR pch = FileName->Buffer + 4;
5296 DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
5297
5298 Size = Length + sizeof(WCHAR);
5299 if (*pdwBytes == 0)
5300 {
5301 *pdwBytes = Size;
5302 bSuccess = TRUE;
5303 }
5304 else if (pBuffer)
5305 {
5306 if (*pdwBytes >= Size)
5307 {
5308 RtlCopyMemory(pBuffer, pch, Size);
5309 }
5310 *pdwBytes = Size;
5311 bSuccess = TRUE;
5312 }
5313 }
5314 break;
5315
5316 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
5317 Size = sizeof(BOOL);
5318 if (*pdwBytes == 0)
5319 {
5320 *pdwBytes = Size;
5321 bSuccess = TRUE;
5322 }
5323 else if (pBuffer)
5324 {
5325 if (*pdwBytes >= Size)
5326 {
5327 *(BOOL*)pBuffer = Count == 0;
5328 }
5329 *pdwBytes = Size;
5330 bSuccess = TRUE;
5331 }
5332 break;
5333 }
5334 ExFreePoolWithTag(FamInfo, TAG_FINF);
5335
5336 return bSuccess;
5337 }
5338
5339
5340 BOOL
5341 FASTCALL
5342 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
5343 {
5344 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
5345 Info->iTechnology = RI_TECH_BITMAP;
5346 else
5347 {
5348 if (FT_IS_SCALABLE(Font->SharedFace->Face))
5349 Info->iTechnology = RI_TECH_SCALABLE;
5350 else
5351 Info->iTechnology = RI_TECH_FIXED;
5352 }
5353 Info->iUniq = Font->FontObj.iUniq;
5354 Info->dwUnknown = -1;
5355 return TRUE;
5356 }
5357
5358
5359 DWORD
5360 FASTCALL
5361 ftGdiGetKerningPairs( PFONTGDI Font,
5362 DWORD cPairs,
5363 LPKERNINGPAIR pKerningPair)
5364 {
5365 DWORD Count = 0;
5366 INT i = 0;
5367 FT_Face face = Font->SharedFace->Face;
5368
5369 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
5370 {
5371 FT_UInt previous_index = 0, glyph_index = 0;
5372 FT_ULong char_code, char_previous;
5373 FT_Vector delta;
5374
5375 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
5376
5377 IntLockFreeType();
5378
5379 while (glyph_index)
5380 {
5381 if (previous_index && glyph_index)
5382 {
5383 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
5384
5385 if (pKerningPair && cPairs)
5386 {
5387 pKerningPair[i].wFirst = char_previous;
5388 pKerningPair[i].wSecond = char_code;
5389 pKerningPair[i].iKernAmount = delta.x;
5390 i++;
5391 if (i == cPairs) break;
5392 }
5393 Count++;
5394 }
5395 previous_index = glyph_index;
5396 char_previous = char_code;
5397 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
5398 }
5399 IntUnLockFreeType();
5400 }
5401 return Count;
5402 }
5403
5404
5405 ///////////////////////////////////////////////////////////////////////////
5406 //
5407 // Functions needing sorting.
5408 //
5409 ///////////////////////////////////////////////////////////////////////////
5410
5411 LONG FASTCALL
5412 IntGetFontFamilyInfo(HDC Dc,
5413 const LOGFONTW *SafeLogFont,
5414 PFONTFAMILYINFO SafeInfo,
5415 LONG InfoCount)
5416 {
5417 LONG AvailCount = 0;
5418 PPROCESSINFO Win32Process;
5419
5420 /* Enumerate font families in the global list */
5421 IntLockGlobalFonts();
5422 if (!GetFontFamilyInfoForList(SafeLogFont, SafeInfo, NULL, &AvailCount,
5423 InfoCount, &g_FontListHead))
5424 {
5425 IntUnLockGlobalFonts();
5426 return -1;
5427 }
5428 IntUnLockGlobalFonts();
5429
5430 /* Enumerate font families in the process local list */
5431 Win32Process = PsGetCurrentProcessWin32Process();
5432 IntLockProcessPrivateFonts(Win32Process);
5433 if (!GetFontFamilyInfoForList(SafeLogFont, SafeInfo, NULL, &AvailCount, InfoCount,
5434 &Win32Process->PrivateFontListHead))
5435 {
5436 IntUnLockProcessPrivateFonts(Win32Process);
5437 return -1;
5438 }
5439 IntUnLockProcessPrivateFonts(Win32Process);
5440
5441 /* Enumerate font families in the registry */
5442 if (!GetFontFamilyInfoForSubstitutes(SafeLogFont, SafeInfo, &AvailCount, InfoCount))
5443 {
5444 return -1;
5445 }
5446
5447 return AvailCount;
5448 }
5449
5450 LONG NTAPI
5451 NtGdiGetFontFamilyInfo(HDC Dc,
5452 const LOGFONTW *UnsafeLogFont,
5453 PFONTFAMILYINFO UnsafeInfo,
5454 LPLONG UnsafeInfoCount)
5455 {
5456 NTSTATUS Status;
5457 LOGFONTW LogFont;
5458 PFONTFAMILYINFO Info;
5459 LONG GotCount, AvailCount, SafeInfoCount;
5460 ULONG DataSize;
5461
5462 if (UnsafeLogFont == NULL || UnsafeInfo == NULL || UnsafeInfoCount == NULL)
5463 {
5464 EngSetLastError(ERROR_INVALID_PARAMETER);
5465 return -1;
5466 }
5467
5468 Status = MmCopyFromCaller(&SafeInfoCount, UnsafeInfoCount, sizeof(SafeInfoCount));
5469 if (!NT_SUCCESS(Status))
5470 {
5471 EngSetLastError(ERROR_INVALID_PARAMETER);
5472 return -1;
5473 }
5474 GotCount = 0;
5475 Status = MmCopyToCaller(UnsafeInfoCount, &GotCount, sizeof(*UnsafeInfoCount));
5476 if (!NT_SUCCESS(Status))
5477 {
5478 EngSetLastError(ERROR_INVALID_PARAMETER);
5479 return -1;
5480 }
5481 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
5482 if (!NT_SUCCESS(Status))
5483 {
5484 EngSetLastError(ERROR_INVALID_PARAMETER);
5485 return -1;
5486 }
5487 if (SafeInfoCount <= 0)
5488 {
5489 EngSetLastError(ERROR_INVALID_PARAMETER);
5490 return -1;
5491 }
5492
5493 /* Allocate space for a safe copy */
5494 Status = RtlULongMult(SafeInfoCount, sizeof(FONTFAMILYINFO), &DataSize);
5495 if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
5496 {
5497 DPRINT1("Overflowed.\n");
5498 EngSetLastError(ERROR_INVALID_PARAMETER);
5499 return -1;
5500 }
5501 Info = ExAllocatePoolWithTag(PagedPool, DataSize, GDITAG_TEXT);
5502 if (Info == NULL)
5503 {
5504 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5505 return -1;
5506 }
5507
5508 /* Retrieve the information */
5509 AvailCount = IntGetFontFamilyInfo(Dc, &LogFont, Info, SafeInfoCount);
5510 GotCount = min(AvailCount, SafeInfoCount);
5511 SafeInfoCount = AvailCount;
5512
5513 /* Return data to caller */
5514 if (GotCount > 0)
5515 {
5516 Status = RtlULongMult(GotCount, sizeof(FONTFAMILYINFO), &DataSize);
5517 if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
5518 {
5519 DPRINT1("Overflowed.\n");
5520 ExFreePoolWithTag(Info, GDITAG_TEXT);
5521 EngSetLastError(ERROR_INVALID_PARAMETER);
5522 return -1;
5523 }
5524 Status = MmCopyToCaller(UnsafeInfo, Info, DataSize);
5525 if (!NT_SUCCESS(Status))
5526 {
5527 ExFreePoolWithTag(Info, GDITAG_TEXT);
5528 EngSetLastError(ERROR_INVALID_PARAMETER);
5529 return -1;
5530 }
5531 Status = MmCopyToCaller(UnsafeInfoCount, &SafeInfoCount, sizeof(*UnsafeInfoCount));
5532 if (!NT_SUCCESS(Status))
5533 {
5534 ExFreePoolWithTag(Info, GDITAG_TEXT);
5535 EngSetLastError(ERROR_INVALID_PARAMETER);
5536 return -1;
5537 }
5538 }
5539
5540 ExFreePoolWithTag(Info, GDITAG_TEXT);
5541
5542 return GotCount;
5543 }
5544
5545 FORCEINLINE
5546 LONG
5547 ScaleLong(LONG lValue, PFLOATOBJ pef)
5548 {
5549 FLOATOBJ efTemp;
5550
5551 /* Check if we have scaling different from 1 */
5552 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
5553 {
5554 /* Need to multiply */
5555 FLOATOBJ_SetLong(&efTemp, lValue);
5556 FLOATOBJ_Mul(&efTemp, pef);
5557 lValue = FLOATOBJ_GetLong(&efTemp);
5558 }
5559
5560 return lValue;
5561 }
5562
5563 FORCEINLINE LONG FASTCALL
5564 IntNormalizeAngle(LONG nTenthAngle)
5565 {
5566 const LONG nFullAngle = 360 * 10;
5567 nTenthAngle %= nFullAngle;
5568 return (nTenthAngle + nFullAngle) % nFullAngle;
5569 }
5570
5571 BOOL
5572 APIENTRY
5573 IntExtTextOutW(
5574 IN PDC dc,
5575 IN INT XStart,
5576 IN INT YStart,
5577 IN UINT fuOptions,
5578 IN OPTIONAL PRECTL lprc,
5579 IN LPCWSTR String,
5580 IN INT Count,
5581 IN OPTIONAL LPINT Dx,
5582 IN DWORD dwCodePage)
5583 {
5584 /*
5585 * FIXME:
5586 * Call EngTextOut, which does the real work (calling DrvTextOut where
5587 * appropriate)
5588 */
5589
5590 PDC_ATTR pdcattr;
5591 SURFOBJ *SurfObj;
5592 SURFACE *psurf = NULL;
5593 int error, glyph_index, i;
5594 FT_Face face;
5595 FT_GlyphSlot glyph;
5596 FT_BitmapGlyph realglyph;
5597 LONGLONG TextLeft64, TextTop64, DeltaX64, DeltaY64, XStart64, YStart64;
5598 ULONG previous;
5599 FT_Bool use_kerning;
5600 RECTL DestRect, MaskRect;
5601 POINTL SourcePoint, BrushOrigin;
5602 HBITMAP HSourceGlyph;
5603 SURFOBJ *SourceGlyphSurf;
5604 SIZEL bitSize;
5605 FONTOBJ *FontObj;
5606 PFONTGDI FontGDI;
5607 PTEXTOBJ TextObj = NULL;
5608 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
5609 FT_Render_Mode RenderMode;
5610 BOOLEAN Render;
5611 POINT Start;
5612 BOOL DoBreak = FALSE;
5613 USHORT DxShift;
5614 PMATRIX pmxWorldToDevice;
5615 LONG lfEscapement, lfWidth;
5616 FLOATOBJ Scale;
5617 LOGFONTW *plf;
5618 BOOL EmuBold, EmuItalic;
5619 int thickness;
5620 BOOL bResult;
5621 FT_Matrix mat = identityMat, matWidth, matEscape, matWorld;
5622 FT_Vector vecs[9];
5623
5624 /* Check if String is valid */
5625 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
5626 {
5627 EngSetLastError(ERROR_INVALID_PARAMETER);
5628 return FALSE;
5629 }
5630
5631 Render = IntIsFontRenderingEnabled();
5632
5633 if (PATH_IsPathOpen(dc->dclevel))
5634 {
5635 bResult = PATH_ExtTextOut(dc,
5636 XStart,
5637 YStart,
5638 fuOptions,
5639 (const RECTL *)lprc,
5640 String,
5641 Count,
5642 (const INT *)Dx);
5643 return bResult;
5644 }
5645
5646 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
5647
5648 if (!dc->dclevel.pSurface)
5649 {
5650 /* Memory DC with no surface selected */
5651 bResult = TRUE;
5652 goto Cleanup;
5653 }
5654
5655 pdcattr = dc->pdcattr;
5656
5657 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
5658 {
5659 IntLPtoDP(dc, (POINT *)lprc, 2);
5660 }
5661
5662 if (pdcattr->flTextAlign & TA_UPDATECP)
5663 {
5664 IntGetCurrentPositionEx(dc, &Start);
5665 }
5666 else
5667 {
5668 Start.x = XStart;
5669 Start.y = YStart;
5670 }
5671
5672 SourcePoint.x = 0;
5673 SourcePoint.y = 0;
5674 MaskRect.left = 0;
5675 MaskRect.top = 0;
5676 BrushOrigin.x = 0;
5677 BrushOrigin.y = 0;
5678
5679 if ((fuOptions & ETO_OPAQUE) && lprc)
5680 {
5681 DestRect.left = lprc->left;
5682 DestRect.top = lprc->top;
5683 DestRect.right = lprc->right;
5684 DestRect.bottom = lprc->bottom;
5685
5686 DestRect.left += dc->ptlDCOrig.x;
5687 DestRect.top += dc->ptlDCOrig.y;
5688 DestRect.right += dc->ptlDCOrig.x;
5689 DestRect.bottom += dc->ptlDCOrig.y;
5690
5691 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5692 {
5693 IntUpdateBoundsRect(dc, &DestRect);
5694 }
5695
5696 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5697 DC_vUpdateBackgroundBrush(dc);
5698 if (dc->dctype == DCTYPE_DIRECT)
5699 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5700
5701 psurf = dc->dclevel.pSurface;
5702 IntEngBitBlt(
5703 &psurf->SurfObj,
5704 NULL,
5705 NULL,
5706 (CLIPOBJ *)&dc->co,
5707 NULL,
5708 &DestRect,
5709 &SourcePoint,
5710 &SourcePoint,
5711 &dc->eboBackground.BrushObject,
5712 &BrushOrigin,
5713 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5714
5715 if (dc->dctype == DCTYPE_DIRECT)
5716 MouseSafetyOnDrawEnd(dc->ppdev);
5717
5718 fuOptions &= ~ETO_OPAQUE;
5719 }
5720 else
5721 {
5722 if (pdcattr->jBkMode == OPAQUE)
5723 {
5724 fuOptions |= ETO_OPAQUE;
5725 }
5726 }
5727
5728 TextObj = RealizeFontInit(pdcattr->hlfntNew);
5729 if (TextObj == NULL)
5730 {
5731 bResult = FALSE;
5732 goto Cleanup;
5733 }
5734
5735 FontObj = TextObj->Font;
5736 ASSERT(FontObj);
5737 FontGDI = ObjToGDI(FontObj, FONT);
5738 ASSERT(FontGDI);
5739
5740 IntLockFreeType();
5741 face = FontGDI->SharedFace->Face;
5742
5743 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5744 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
5745 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
5746 if (FT_IS_SCALABLE(face))
5747 {
5748 lfEscapement = IntNormalizeAngle(plf->lfEscapement);
5749 lfWidth = labs(plf->lfWidth);
5750 }
5751 else
5752 {
5753 lfEscapement = lfWidth = 0;
5754 }
5755
5756 if (Render)
5757 RenderMode = IntGetFontRenderMode(plf);
5758 else
5759 RenderMode = FT_RENDER_MODE_MONO;
5760
5761 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
5762 {
5763 IntUnLockFreeType();
5764 bResult = FALSE;
5765 goto Cleanup;
5766 }
5767
5768 /* NOTE: Don't trust face->size->metrics.ascender and descender values. */
5769 DC_vUpdateWorldToDevice(dc);
5770 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
5771 {
5772 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
5773 }
5774 else
5775 {
5776 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
5777 }
5778
5779 IntWidthMatrix(face, &matWidth, lfWidth);
5780 FT_Matrix_Multiply(&matWidth, &mat);
5781
5782 IntEscapeMatrix(&matEscape, lfEscapement);
5783 FT_Matrix_Multiply(&matEscape, &mat);
5784
5785 FtMatrixFromMx(&matWorld, pmxWorldToDevice);
5786 matWorld.yx = -matWorld.yx;
5787 matWorld.xy = -matWorld.xy;
5788 FT_Matrix_Multiply(&matWorld, &mat);
5789
5790 FT_Set_Transform(face, &mat, NULL);
5791
5792 // Calculate displacement of the text.
5793 DeltaX64 = DeltaY64 = 0;
5794 DxShift = fuOptions & ETO_PDY ? 1 : 0;
5795 use_kerning = FT_HAS_KERNING(face);
5796 previous = 0;
5797 if ((fuOptions & ETO_OPAQUE) ||
5798 (pdcattr->flTextAlign & (TA_CENTER | TA_RIGHT)) ||
5799 memcmp(&mat, &identityMat, sizeof(mat)) != 0 ||
5800 plf->lfUnderline || plf->lfStrikeOut)
5801 {
5802 for (i = 0; i < Count; ++i)
5803 {
5804 glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions);
5805
5806 // FIXME: Use FT_LOAD_BITMAP_METRICS_ONLY or cache.
5807 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5808 if (error)
5809 {
5810 DPRINT1("Failed to load glyph! [index: %d]\n", glyph_index);
5811 IntUnLockFreeType();
5812 bResult = FALSE;
5813 goto Cleanup;
5814 }
5815
5816 glyph = face->glyph;
5817 if (EmuBold)
5818 FT_GlyphSlot_Embolden(glyph);
5819 if (EmuItalic)
5820 FT_GlyphSlot_Oblique(glyph);
5821 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5822 if (!realglyph)
5823 {
5824 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5825 IntUnLockFreeType();
5826 bResult = FALSE;
5827 goto Cleanup;
5828 }
5829
5830 /* retrieve kerning distance and move pen position */
5831 if (use_kerning && previous && glyph_index && Dx == NULL)
5832 {
5833 FT_Vector delta;
5834 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5835 DeltaX64 += delta.x;
5836 DeltaY64 -= delta.y;
5837 }
5838
5839 if (Dx == NULL)
5840 {
5841 DeltaX64 += realglyph->root.advance.x >> 10;
5842 DeltaY64 -= realglyph->root.advance.y >> 10;
5843 }
5844 else
5845 {
5846 // FIXME this should probably be a matrix transform with DeltaY64 as well.
5847 Scale = pdcattr->mxWorldToDevice.efM11;
5848 if (FLOATOBJ_Equal0(&Scale))
5849 FLOATOBJ_Set1(&Scale);
5850
5851 /* do the shift before multiplying to preserve precision */
5852 FLOATOBJ_MulLong(&Scale, Dx[i << DxShift] << 6);
5853 DeltaX64 += FLOATOBJ_GetLong(&Scale);
5854 }
5855
5856 if (DxShift)
5857 {
5858 DeltaY64 -= Dx[2 * i + 1] << 6;
5859 }
5860
5861 previous = glyph_index;
5862
5863 FT_Done_Glyph((FT_Glyph)realglyph);
5864 }
5865 }
5866
5867 // Process the X and Y alignments.
5868 if ((pdcattr->flTextAlign & TA_CENTER) == TA_CENTER)
5869 {
5870 XStart64 = -DeltaX64 / 2;
5871 YStart64 = -DeltaY64 / 2;
5872 }
5873 else if ((pdcattr->flTextAlign & TA_RIGHT) == TA_RIGHT)
5874 {
5875 XStart64 = -DeltaX64;
5876 YStart64 = -DeltaY64;
5877 }
5878 else
5879 {
5880 XStart64 = YStart64 = 0;
5881 }
5882
5883 psurf = dc->dclevel.pSurface;
5884 SurfObj = &psurf->SurfObj ;
5885
5886 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
5887 DC_vUpdateBackgroundBrush(dc) ;
5888
5889 if (dc->pdcattr->ulDirty_ & DIRTY_TEXT)
5890 DC_vUpdateTextBrush(dc) ;
5891
5892 thickness = 1;
5893 if (face->units_per_EM)
5894 {
5895 thickness = face->underline_thickness *
5896 face->size->metrics.y_ppem / face->units_per_EM;
5897 if (thickness <= 0)
5898 thickness = 1;
5899 }
5900
5901 /* Process the vertical alignment */
5902 #define VALIGN_MASK (TA_TOP | TA_BASELINE | TA_BOTTOM)
5903 RtlZeroMemory(vecs, sizeof(vecs));
5904 if ((pdcattr->flTextAlign & VALIGN_MASK) == TA_BASELINE)
5905 {
5906 vecs[1].y = -FontGDI->tmAscent << 16; // upper left
5907 vecs[4].y = 0; // baseline
5908 vecs[0].y = FontGDI->tmDescent << 16; // lower left
5909 }
5910 else if ((pdcattr->flTextAlign & VALIGN_MASK) == TA_BOTTOM)
5911 {
5912 vecs[1].y = -FontGDI->tmHeight << 16; // upper left
5913 vecs[4].y = -FontGDI->tmDescent << 16; // baseline
5914 vecs[0].y = 0; // lower left
5915 }
5916 else /* TA_TOP */
5917 {
5918 vecs[1].y = 0; // upper left
5919 vecs[4].y = FontGDI->tmAscent << 16; // baseline
5920 vecs[0].y = FontGDI->tmHeight << 16; // lower left
5921 }
5922 vecs[2] = vecs[1]; // upper right
5923 vecs[3] = vecs[0]; // lower right
5924 #undef VALIGN_MASK
5925
5926 // underline
5927 if (plf->lfUnderline)
5928 {
5929 int position = 0;
5930 if (face->units_per_EM)
5931 {
5932 position = face->underline_position *
5933 face->size->metrics.y_ppem / face->units_per_EM;
5934 }
5935 vecs[5].y = vecs[6].y = vecs[4].y - (position << 16);
5936 }
5937
5938 // strike through
5939 if (plf->lfStrikeOut)
5940 {
5941 vecs[7].y = vecs[8].y = vecs[4].y - ((FontGDI->tmAscent / 3) << 16);
5942 }
5943
5944 // invert y axis
5945 IntEscapeMatrix(&matEscape, -lfEscapement);
5946
5947 matWorld.yx = -matWorld.yx;
5948 matWorld.xy = -matWorld.xy;
5949
5950 // convert vecs
5951 for (i = 0; i < 9; ++i)
5952 {
5953 FT_Vector_Transform(&vecs[i], &matWidth);
5954 FT_Vector_Transform(&vecs[i], &matEscape);
5955 FT_Vector_Transform(&vecs[i], &matWorld);
5956 }
5957 vecs[2].x += DeltaX64 << 10;
5958 vecs[2].y += DeltaY64 << 10; // upper right
5959 vecs[3].x += DeltaX64 << 10;
5960 vecs[3].y += DeltaY64 << 10; // lower right
5961 vecs[6].x += DeltaX64 << 10;
5962 vecs[6].y += DeltaY64 << 10; // underline right
5963 vecs[8].x += DeltaX64 << 10;
5964 vecs[8].y += DeltaY64 << 10; // strike through right
5965
5966 {
5967 POINT pt;
5968 pt.x = Start.x + (XStart64 >> 6);
5969 pt.y = Start.y + (YStart64 >> 6);
5970 IntLPtoDP(dc, &pt, 1);
5971
5972 for (i = 0; i < 9; ++i)
5973 {
5974 vecs[i].x += pt.x << 16;
5975 vecs[i].y += pt.y << 16;
5976 vecs[i].x >>= 16;
5977 vecs[i].y >>= 16;
5978 vecs[i].x += dc->ptlDCOrig.x;
5979 vecs[i].y += dc->ptlDCOrig.y;
5980 }
5981 }
5982
5983 if (fuOptions & ETO_OPAQUE)
5984 {
5985 /* Draw background */
5986 RECTL Rect;
5987 RtlZeroMemory(&Rect, sizeof(Rect));
5988
5989 if ((mat.xy == 0 && mat.yx == 0) || (mat.xx == 0 && mat.yy == 0))
5990 {
5991 Rect.left = Rect.top = MAXLONG;
5992 Rect.right = Rect.bottom = MINLONG;
5993 for (i = 0; i < 4; ++i)
5994 {
5995 Rect.left = min(Rect.left, vecs[i].x);
5996 Rect.top = min(Rect.top, vecs[i].y);
5997 Rect.right = max(Rect.right, vecs[i].x);
5998 Rect.bottom = max(Rect.bottom, vecs[i].y);
5999 }
6000 }
6001 else
6002 {
6003 // FIXME: Use vecs[0] ... vecs[3] and EngFillPath
6004 }
6005
6006 if (dc->fs & (DC_ACCUM_APP | DC_ACCUM_WMGR))
6007 {
6008 IntUpdateBoundsRect(dc, &Rect);
6009 }
6010
6011 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
6012 DC_vUpdateBackgroundBrush(dc);
6013 if (dc->dctype == DCTYPE_DIRECT)
6014 MouseSafetyOnDrawStart(dc->ppdev, Rect.left, Rect.top, Rect.right, Rect.bottom);
6015
6016 SourcePoint.x = SourcePoint.y = 0;
6017 BrushOrigin.x = BrushOrigin.y = 0;
6018
6019 psurf = dc->dclevel.pSurface;
6020 IntEngBitBlt(
6021 &psurf->SurfObj,
6022 NULL,
6023 NULL,
6024 (CLIPOBJ *)&dc->co,
6025 NULL,
6026 &Rect,
6027 &SourcePoint,
6028 &SourcePoint,
6029 &dc->eboBackground.BrushObject,
6030 &BrushOrigin,
6031 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
6032
6033 if (dc->dctype == DCTYPE_DIRECT)
6034 MouseSafetyOnDrawEnd(dc->ppdev);
6035 }
6036
6037 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
6038 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
6039
6040 // The main rendering loop.
6041 bResult = TRUE;
6042 TextLeft64 = vecs[4].x << 6;
6043 TextTop64 = vecs[4].y << 6;
6044 previous = 0;
6045 for (i = 0; i < Count; ++i)
6046 {
6047 BOOL bNeedCache = (!EmuBold && !EmuItalic &&
6048 memcmp(&mat, &identityMat, sizeof(mat)) == 0);
6049 glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions);
6050 realglyph = NULL;
6051 if (bNeedCache)
6052 {
6053 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
6054 RenderMode, pmxWorldToDevice);
6055 }
6056 if (!realglyph)
6057 {
6058 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6059 if (error)
6060 {
6061 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
6062 bResult = FALSE;
6063 break;
6064 }
6065 glyph = face->glyph;
6066 if (bNeedCache)
6067 {
6068 realglyph = ftGdiGlyphCacheSet(face,
6069 glyph_index,
6070 plf->lfHeight,
6071 pmxWorldToDevice,
6072 glyph,
6073 RenderMode);
6074 }
6075 else
6076 {
6077 if (EmuBold)
6078 FT_GlyphSlot_Embolden(glyph);
6079 if (EmuItalic)
6080 FT_GlyphSlot_Oblique(glyph);
6081 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
6082 }
6083 if (!realglyph)
6084 {
6085 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
6086 bResult = FALSE;
6087 break;
6088 }
6089 }
6090
6091 /* retrieve kerning distance and move pen position */
6092 if (use_kerning && previous && glyph_index && NULL == Dx)
6093 {
6094 FT_Vector delta;
6095 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
6096 TextLeft64 += delta.x;
6097 TextTop64 -= delta.y;
6098 }
6099 DPRINT("TextLeft64: %I64d\n", TextLeft64);
6100 DPRINT("TextTop64: %I64d\n", TextTop64);
6101 DPRINT("Advance: %d\n", realglyph->root.advance.x);
6102
6103 DestRect.left = ((TextLeft64 + 32) >> 6) + realglyph->left;
6104 DestRect.right = DestRect.left + realglyph->bitmap.width;
6105 DestRect.top = ((TextTop64 + 32) >> 6) - realglyph->top;
6106 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
6107
6108 bitSize.cx = realglyph->bitmap.width;
6109 bitSize.cy = realglyph->bitmap.rows;
6110 MaskRect.right = realglyph->bitmap.width;
6111 MaskRect.bottom = realglyph->bitmap.rows;
6112
6113 /* Check if the bitmap has any pixels */
6114 if ((bitSize.cx != 0) && (bitSize.cy != 0))
6115 {
6116 /*
6117 * We should create the bitmap out of the loop at the biggest possible
6118 * glyph size. Then use memset with 0 to clear it and sourcerect to
6119 * limit the work of the transbitblt.
6120 */
6121 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
6122 BMF_8BPP, BMF_TOPDOWN,
6123 realglyph->bitmap.buffer);
6124 if ( !HSourceGlyph )
6125 {
6126 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
6127 bResult = FALSE;
6128 if (EmuBold || EmuItalic)
6129 {
6130 FT_Done_Glyph((FT_Glyph)realglyph);
6131 }
6132
6133 break;
6134 }
6135 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
6136 if ( !SourceGlyphSurf )
6137 {
6138 EngDeleteSurface((HSURF)HSourceGlyph);
6139 DPRINT1("WARNING: EngLockSurface() failed!\n");
6140 bResult = FALSE;
6141 if (EmuBold || EmuItalic)
6142 {
6143 FT_Done_Glyph((FT_Glyph)realglyph);
6144 }
6145
6146 break;
6147 }
6148
6149 /*
6150 * Use the font data as a mask to paint onto the DCs surface using a
6151 * brush.
6152 */
6153 if (lprc && (fuOptions & ETO_CLIPPED) &&
6154 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
6155 {
6156 // We do the check '>=' instead of '>' to possibly save an iteration
6157 // through this loop, since it's breaking after the drawing is done,
6158 // and x is always incremented.
6159 DestRect.right = lprc->right + dc->ptlDCOrig.x;
6160 DoBreak = TRUE;
6161 }
6162 if (lprc && (fuOptions & ETO_CLIPPED) &&
6163 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
6164 {
6165 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
6166 }
6167
6168 if (dc->dctype == DCTYPE_DIRECT)
6169 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
6170
6171 if (!IntEngMaskBlt(
6172 SurfObj,
6173 SourceGlyphSurf,
6174 (CLIPOBJ *)&dc->co,
6175 &exloRGB2Dst.xlo,
6176 &exloDst2RGB.xlo,
6177 &DestRect,
6178 (PPOINTL)&MaskRect,
6179 &dc->eboText.BrushObject,
6180 &BrushOrigin))
6181 {
6182 DPRINT1("Failed to MaskBlt a glyph!\n");
6183 }
6184
6185 if (dc->dctype == DCTYPE_DIRECT)
6186 MouseSafetyOnDrawEnd(dc->ppdev) ;
6187
6188 EngUnlockSurface(SourceGlyphSurf);
6189 EngDeleteSurface((HSURF)HSourceGlyph);
6190 }
6191
6192 if (DoBreak)
6193 {
6194 if (EmuBold || EmuItalic)
6195 {
6196 FT_Done_Glyph((FT_Glyph)realglyph);
6197 }
6198
6199 break;
6200 }
6201
6202 if (NULL == Dx)
6203 {
6204 TextLeft64 += realglyph->root.advance.x >> 10;
6205 TextTop64 -= realglyph->root.advance.y >> 10;
6206 DPRINT("New TextLeft64: %I64d\n", TextLeft64);
6207 DPRINT("New TextTop64: %I64d\n", TextTop64);
6208 }
6209 else
6210 {
6211 // FIXME this should probably be a matrix transform with TextTop64 as well.
6212 Scale = pdcattr->mxWorldToDevice.efM11;
6213 if (FLOATOBJ_Equal0(&Scale))
6214 FLOATOBJ_Set1(&Scale);
6215
6216 /* do the shift before multiplying to preserve precision */
6217 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
6218 TextLeft64 += FLOATOBJ_GetLong(&Scale);
6219 DPRINT("New TextLeft64 2: %I64d\n", TextLeft64);
6220 }
6221
6222 if (DxShift)
6223 {
6224 TextTop64 -= Dx[2 * i + 1] << 6;
6225 }
6226
6227 previous = glyph_index;
6228
6229 /* No cache, so clean up */
6230 if (!bNeedCache)
6231 {
6232 FT_Done_Glyph((FT_Glyph)realglyph);
6233 }
6234 }
6235
6236 if (plf->lfUnderline || plf->lfStrikeOut)
6237 {
6238 INT x0 = min(vecs[0].x, vecs[2].x);
6239 INT y0 = min(vecs[0].y, vecs[2].y);
6240 INT x1 = max(vecs[0].x, vecs[2].x);
6241 INT y1 = max(vecs[0].y, vecs[2].y);
6242 if (dc->dctype == DCTYPE_DIRECT)
6243 MouseSafetyOnDrawStart(dc->ppdev, x0, y0, x1, y1);
6244 }
6245
6246 if (plf->lfUnderline)
6247 {
6248 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
6249 {
6250 LONG dx = (LONG)(DeltaX64 >> 6), dy = (LONG)(DeltaY64 >> 6);
6251 if (labs(dx) > labs(dy))
6252 {
6253 // move vertical
6254 EngLineTo(SurfObj, (CLIPOBJ *)&dc->co,
6255 &dc->eboText.BrushObject,
6256 vecs[5].x, vecs[5].y + i,
6257 vecs[6].x, vecs[6].y + i,
6258 NULL, ROP2_TO_MIX(R2_COPYPEN));
6259 }
6260 else
6261 {
6262 // move horizontal
6263 EngLineTo(SurfObj, (CLIPOBJ *)&dc->co,
6264 &dc->eboText.BrushObject,
6265 vecs[5].x + i, vecs[5].y,
6266 vecs[6].x + i, vecs[6].y,
6267 NULL, ROP2_TO_MIX(R2_COPYPEN));
6268 }
6269 }
6270 }
6271
6272 if (plf->lfStrikeOut)
6273 {
6274 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
6275 {
6276 LONG dx = (LONG)(DeltaX64 >> 6), dy = (LONG)(DeltaY64 >> 6);
6277 if (labs(dx) > labs(dy))
6278 {
6279 // move vertical
6280 EngLineTo(SurfObj, (CLIPOBJ *)&dc->co,
6281 &dc->eboText.BrushObject,
6282 vecs[7].x, vecs[7].y + i,
6283 vecs[8].x, vecs[8].y + i,
6284 NULL, ROP2_TO_MIX(R2_COPYPEN));
6285 }
6286 else
6287 {
6288 // move horizontal
6289 EngLineTo(SurfObj, (CLIPOBJ *)&dc->co,
6290 &dc->eboText.BrushObject,
6291 vecs[7].x + i, vecs[7].y,
6292 vecs[8].x + i, vecs[8].y,
6293 NULL, ROP2_TO_MIX(R2_COPYPEN));
6294 }
6295 }
6296 }
6297
6298 if (plf->lfUnderline || plf->lfStrikeOut)
6299 {
6300 if (dc->dctype == DCTYPE_DIRECT)
6301 MouseSafetyOnDrawEnd(dc->ppdev);
6302 }
6303
6304 if (pdcattr->flTextAlign & TA_UPDATECP)
6305 {
6306 pdcattr->ptlCurrent.x = vecs[2].x - dc->ptlDCOrig.x;
6307 pdcattr->ptlCurrent.y = vecs[2].y - dc->ptlDCOrig.y;
6308 IntDPtoLP(dc, &pdcattr->ptlCurrent, 1);
6309 pdcattr->ulDirty_ &= ~DIRTY_PTLCURRENT;
6310 pdcattr->ulDirty_ |= (DIRTY_PTFXCURRENT | DIRTY_STYLESTATE);
6311 }
6312
6313 IntUnLockFreeType();
6314
6315 EXLATEOBJ_vCleanup(&exloRGB2Dst);
6316 EXLATEOBJ_vCleanup(&exloDst2RGB);
6317
6318 Cleanup:
6319
6320 DC_vFinishBlit(dc, NULL);
6321
6322 if (TextObj != NULL)
6323 TEXTOBJ_UnlockText(TextObj);
6324
6325 return bResult;
6326 }
6327
6328
6329 BOOL
6330 APIENTRY
6331 GreExtTextOutW(
6332 IN HDC hDC,
6333 IN INT XStart,
6334 IN INT YStart,
6335 IN UINT fuOptions,
6336 IN OPTIONAL PRECTL lprc,
6337 IN LPCWSTR String,
6338 IN INT Count,
6339 IN OPTIONAL LPINT Dx,
6340 IN DWORD dwCodePage)
6341 {
6342 BOOL bResult;
6343 DC *dc;
6344
6345 // TODO: Write test-cases to exactly match real Windows in different
6346 // bad parameters (e.g. does Windows check the DC or the RECT first?).
6347 dc = DC_LockDc(hDC);
6348 if (!dc)
6349 {
6350 EngSetLastError(ERROR_INVALID_HANDLE);
6351 return FALSE;
6352 }
6353
6354 bResult = IntExtTextOutW( dc,
6355 XStart,
6356 YStart,
6357 fuOptions,
6358 lprc,
6359 String,
6360 Count,
6361 Dx,
6362 dwCodePage );
6363
6364 DC_UnlockDc(dc);
6365
6366 return bResult;
6367 }
6368
6369 #define STACK_TEXT_BUFFER_SIZE 100
6370 BOOL
6371 APIENTRY
6372 NtGdiExtTextOutW(
6373 IN HDC hDC,
6374 IN INT XStart,
6375 IN INT YStart,
6376 IN UINT fuOptions,
6377 IN OPTIONAL LPRECT UnsafeRect,
6378 IN LPWSTR UnsafeString,
6379 IN INT Count,
6380 IN OPTIONAL LPINT UnsafeDx,
6381 IN DWORD dwCodePage)
6382 {
6383 BOOL Result = FALSE;
6384 NTSTATUS Status = STATUS_SUCCESS;
6385 RECTL SafeRect;
6386 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
6387 PVOID Buffer = LocalBuffer;
6388 LPCWSTR SafeString = NULL;
6389 LPINT SafeDx = NULL;
6390 ULONG BufSize, StringSize, DxSize = 0;
6391
6392 /* Check if String is valid */
6393 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
6394 {
6395 EngSetLastError(ERROR_INVALID_PARAMETER);
6396 return FALSE;
6397 }
6398
6399 if (Count > 0)
6400 {
6401 /* Calculate buffer size for string and Dx values */
6402 BufSize = StringSize = Count * sizeof(WCHAR);
6403 if (UnsafeDx)
6404 {
6405 /* If ETO_PDY is specified, we have pairs of INTs */
6406 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
6407 BufSize += DxSize;
6408 }
6409
6410 /* Check if our local buffer is large enough */
6411 if (BufSize > STACK_TEXT_BUFFER_SIZE)
6412 {
6413 /* It's not, allocate a temp buffer */
6414 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
6415 if (!Buffer)
6416 {
6417 return FALSE;
6418 }
6419 }
6420
6421 /* Probe and copy user mode data to the buffer */
6422 _SEH2_TRY
6423 {
6424 /* Put the Dx before the String to assure alignment of 4 */
6425 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
6426
6427 /* Probe and copy the string */
6428 ProbeForRead(UnsafeString, StringSize, 1);
6429 memcpy((PVOID)SafeString, UnsafeString, StringSize);
6430
6431 /* If we have Dx values... */
6432 if (UnsafeDx)
6433 {
6434 /* ... probe and copy them */
6435 SafeDx = Buffer;
6436 ProbeForRead(UnsafeDx, DxSize, 1);
6437 memcpy(SafeDx, UnsafeDx, DxSize);
6438 }
6439 }
6440 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6441 {
6442 Status = _SEH2_GetExceptionCode();
6443 }
6444 _SEH2_END
6445 if (!NT_SUCCESS(Status))
6446 {
6447 goto cleanup;
6448 }
6449 }
6450
6451 /* If we have a rect, copy it */
6452 if (UnsafeRect)
6453 {
6454 _SEH2_TRY
6455 {
6456 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
6457 SafeRect = *UnsafeRect;
6458 }
6459 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6460 {
6461 Status = _SEH2_GetExceptionCode();
6462 }
6463 _SEH2_END
6464 if (!NT_SUCCESS(Status))
6465 {
6466 goto cleanup;
6467 }
6468 }
6469
6470 /* Finally call the internal routine */
6471 Result = GreExtTextOutW(hDC,
6472 XStart,
6473 YStart,
6474 fuOptions,
6475 &SafeRect,
6476 SafeString,
6477 Count,
6478 SafeDx,
6479 dwCodePage);
6480
6481 cleanup:
6482 /* If we allocated a buffer, free it */
6483 if (Buffer != LocalBuffer)
6484 {
6485 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6486 }
6487
6488 return Result;
6489 }
6490
6491
6492 /*
6493 * @implemented
6494 */
6495 BOOL
6496 APIENTRY
6497 NtGdiGetCharABCWidthsW(
6498 IN HDC hDC,
6499 IN UINT FirstChar,
6500 IN ULONG Count,
6501 IN OPTIONAL PWCHAR UnSafepwch,
6502 IN FLONG fl,
6503 OUT PVOID Buffer)
6504 {
6505 LPABC SafeBuff;
6506 LPABCFLOAT SafeBuffF = NULL;
6507 PDC dc;
6508 PDC_ATTR pdcattr;
6509 PTEXTOBJ TextObj;
6510 PFONTGDI FontGDI;
6511 FT_Face face;
6512 FT_CharMap charmap, found = NULL;
6513 UINT i, glyph_index, BufferSize;
6514 HFONT hFont = 0;
6515 NTSTATUS Status = STATUS_SUCCESS;
6516 PMATRIX pmxWorldToDevice;
6517 PWCHAR Safepwch = NULL;
6518 LOGFONTW *plf;
6519
6520 if (!Buffer)
6521 {
6522 EngSetLastError(ERROR_INVALID_PARAMETER);
6523 return FALSE;
6524 }
6525
6526 if (UnSafepwch)
6527 {
6528 UINT pwchSize = Count * sizeof(WCHAR);
6529 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
6530
6531 if(!Safepwch)
6532 {
6533 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6534 return FALSE;
6535 }
6536
6537 _SEH2_TRY
6538 {
6539 ProbeForRead(UnSafepwch, pwchSize, 1);
6540 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
6541 }
6542 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6543 {
6544 Status = _SEH2_GetExceptionCode();
6545 }
6546 _SEH2_END;
6547 }
6548
6549 if (!NT_SUCCESS(Status))
6550 {
6551 if(Safepwch)
6552 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6553
6554 EngSetLastError(Status);
6555 return FALSE;
6556 }
6557
6558 BufferSize = Count * sizeof(ABC); // Same size!
6559 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6560 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
6561 if (SafeBuff == NULL)
6562 {
6563
6564 if(Safepwch)
6565 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6566
6567 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6568 return FALSE;
6569 }
6570
6571 dc = DC_LockDc(hDC);
6572 if (dc == NULL)
6573 {
6574 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6575
6576 if(Safepwch)
6577 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6578
6579 EngSetLastError(ERROR_INVALID_HANDLE);
6580 return FALSE;
6581 }
6582 pdcattr = dc->pdcattr;
6583 hFont = pdcattr->hlfntNew;
6584 TextObj = RealizeFontInit(hFont);
6585
6586 /* Get the DC's world-to-device transformation matrix */
6587 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6588 DC_UnlockDc(dc);
6589
6590 if (TextObj == NULL)
6591 {
6592 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6593
6594 if(Safepwch)
6595 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6596
6597 EngSetLastError(ERROR_INVALID_HANDLE);
6598 return FALSE;
6599 }
6600
6601 FontGDI = ObjToGDI(TextObj->Font, FONT);
6602
6603 face = FontGDI->SharedFace->Face;
6604 if (face->charmap == NULL)
6605 {
6606 for (i = 0; i < (UINT)face->num_charmaps; i++)
6607 {
6608 charmap = face->charmaps[i];
6609 if (charmap->encoding != 0)
6610 {
6611 found = charmap;
6612 break;
6613 }
6614 }
6615
6616 if (!found)
6617 {
6618 DPRINT1("WARNING: Could not find desired charmap!\n");
6619 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6620
6621 if(Safepwch)
6622 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6623
6624 EngSetLastError(ERROR_INVALID_HANDLE);
6625 return FALSE;
6626 }
6627
6628 IntLockFreeType();
6629 FT_Set_Charmap(face, found);
6630 IntUnLockFreeType();
6631 }
6632
6633 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6634 IntLockFreeType();
6635 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
6636 FtSetCoordinateTransform(face, pmxWorldToDevice);
6637
6638 for (i = FirstChar; i < FirstChar+Count; i++)
6639 {
6640 int adv, lsb, bbx, left, right;
6641
6642 if (Safepwch)
6643 {
6644 glyph_index = get_glyph_index_flagged(face, Safepwch[i - FirstChar], GCABCW_INDICES, fl);
6645 }
6646 else
6647 {
6648 glyph_index = get_glyph_index_flagged(face, i, GCABCW_INDICES, fl);
6649 }
6650 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6651
6652 left = (INT)face->glyph->metrics.horiBearingX & -64;
6653 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
6654 adv = (face->glyph->advance.x + 32) >> 6;
6655
6656 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
6657 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
6658
6659 lsb = left >> 6;
6660 bbx = (right - left) >> 6;
6661 /*
6662 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
6663 */
6664 if (!fl)
6665 {
6666 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
6667 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
6668 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
6669 }
6670 else
6671 {
6672 SafeBuff[i - FirstChar].abcA = lsb;
6673 SafeBuff[i - FirstChar].abcB = bbx;
6674 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
6675 }
6676 }
6677 IntUnLockFreeType();
6678 TEXTOBJ_UnlockText(TextObj);
6679 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6680
6681 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6682
6683 if(Safepwch)
6684 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6685
6686 if (!NT_SUCCESS(Status))
6687 {
6688 SetLastNtError(Status);
6689 return FALSE;
6690 }
6691
6692 DPRINT("NtGdiGetCharABCWidths Worked!\n");
6693 return TRUE;
6694 }
6695
6696 /*
6697 * @implemented
6698 */
6699 BOOL
6700 APIENTRY
6701 NtGdiGetCharWidthW(
6702 IN HDC hDC,
6703 IN UINT FirstChar,
6704 IN UINT Count,
6705 IN OPTIONAL PWCHAR UnSafepwc,
6706 IN FLONG fl,
6707 OUT PVOID Buffer)
6708 {
6709 NTSTATUS Status = STATUS_SUCCESS;
6710 LPINT SafeBuff;
6711 PFLOAT SafeBuffF = NULL;
6712 PDC dc;
6713 PDC_ATTR pdcattr;
6714 PTEXTOBJ TextObj;
6715 PFONTGDI FontGDI;
6716 FT_Face face;
6717 FT_CharMap charmap, found = NULL;
6718 UINT i, glyph_index, BufferSize;
6719 HFONT hFont = 0;
6720 PMATRIX pmxWorldToDevice;
6721 PWCHAR Safepwc = NULL;
6722 LOGFONTW *plf;
6723
6724 if (UnSafepwc)
6725 {
6726 UINT pwcSize = Count * sizeof(WCHAR);
6727 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6728
6729 if(!Safepwc)
6730 {
6731 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6732 return FALSE;
6733 }
6734 _SEH2_TRY
6735 {
6736 ProbeForRead(UnSafepwc, pwcSize, 1);
6737 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6738 }
6739 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6740 {
6741 Status = _SEH2_GetExceptionCode();
6742 }
6743 _SEH2_END;
6744 }
6745
6746 if (!NT_SUCCESS(Status))
6747 {
6748 EngSetLastError(Status);
6749 return FALSE;
6750 }
6751
6752 BufferSize = Count * sizeof(INT); // Same size!
6753 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6754 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
6755 if (SafeBuff == NULL)
6756 {
6757 if(Safepwc)
6758 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6759
6760 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6761 return FALSE;
6762 }
6763
6764 dc = DC_LockDc(hDC);
6765 if (dc == NULL)
6766 {
6767 if(Safepwc)
6768 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6769
6770 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6771 EngSetLastError(ERROR_INVALID_HANDLE);
6772 return FALSE;
6773 }
6774 pdcattr = dc->pdcattr;
6775 hFont = pdcattr->hlfntNew;
6776 TextObj = RealizeFontInit(hFont);
6777 /* Get the DC's world-to-device transformation matrix */
6778 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6779 DC_UnlockDc(dc);
6780
6781 if (TextObj == NULL)
6782 {
6783 if(Safepwc)
6784 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6785
6786 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6787 EngSetLastError(ERROR_INVALID_HANDLE);
6788 return FALSE;
6789 }
6790
6791 FontGDI = ObjToGDI(TextObj->Font, FONT);
6792
6793 face = FontGDI->SharedFace->Face;
6794 if (face->charmap == NULL)
6795 {
6796 for (i = 0; i < (UINT)face->num_charmaps; i++)
6797 {
6798 charmap = face->charmaps[i];
6799 if (charmap->encoding != 0)
6800 {
6801 found = charmap;
6802 break;
6803 }
6804 }
6805
6806 if (!found)
6807 {
6808 DPRINT1("WARNING: Could not find desired charmap!\n");
6809
6810 if(Safepwc)
6811 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6812
6813 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6814 EngSetLastError(ERROR_INVALID_HANDLE);
6815 return FALSE;
6816 }
6817
6818 IntLockFreeType();
6819 FT_Set_Charmap(face, found);
6820 IntUnLockFreeType();
6821 }
6822
6823 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6824 IntLockFreeType();
6825 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
6826 FtSetCoordinateTransform(face, pmxWorldToDevice);
6827
6828 for (i = FirstChar; i < FirstChar+Count; i++)
6829 {
6830 if (Safepwc)
6831 {
6832 glyph_index = get_glyph_index_flagged(face, Safepwc[i - FirstChar], GCW_INDICES, fl);
6833 }
6834 else
6835 {
6836 glyph_index = get_glyph_index_flagged(face, i, GCW_INDICES, fl);
6837 }
6838 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6839 if (!fl)
6840 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
6841 else
6842 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
6843 }
6844 IntUnLockFreeType();
6845 TEXTOBJ_UnlockText(TextObj);
6846 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6847
6848 if(Safepwc)
6849 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6850
6851 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6852 return TRUE;
6853 }
6854
6855
6856 /*
6857 * @implemented
6858 */
6859 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
6860 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
6861 // NOTE: See also GreGetGlyphIndicesW.
6862 __kernel_entry
6863 W32KAPI
6864 DWORD
6865 APIENTRY
6866 NtGdiGetGlyphIndicesW(
6867 _In_ HDC hdc,
6868 _In_reads_opt_(cwc) LPCWSTR pwc,
6869 _In_ INT cwc,
6870 _Out_writes_opt_(cwc) LPWORD pgi,
6871 _In_ DWORD iMode)
6872 {
6873 PDC dc;
6874 PDC_ATTR pdcattr;
6875 PTEXTOBJ TextObj;
6876 PFONTGDI FontGDI;
6877 HFONT hFont = NULL;
6878 NTSTATUS Status = STATUS_SUCCESS;
6879 OUTLINETEXTMETRICW *potm;
6880 INT i;
6881 WCHAR DefChar = 0xffff;
6882 PWSTR Buffer = NULL;
6883 ULONG Size, pwcSize;
6884 PWSTR Safepwc = NULL;
6885 LPCWSTR UnSafepwc = pwc;
6886 LPWORD UnSafepgi = pgi;
6887
6888 /* Check for integer overflow */
6889 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN
6890 return GDI_ERROR;
6891
6892 if (!UnSafepwc && !UnSafepgi)
6893 return cwc;
6894
6895 if (!UnSafepwc || !UnSafepgi)
6896 {
6897 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
6898 return GDI_ERROR;
6899 }
6900
6901 // TODO: Special undocumented case!
6902 if (!pwc && !pgi && (cwc == 0))
6903 {
6904 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n");
6905 return 0;
6906 }
6907
6908 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825
6909 if (cwc == 0)
6910 {
6911 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n");
6912 return GDI_ERROR;
6913 }
6914
6915 dc = DC_LockDc(hdc);
6916 if (!dc)
6917 {
6918 return GDI_ERROR;
6919 }
6920 pdcattr = dc->pdcattr;
6921 hFont = pdcattr->hlfntNew;
6922 TextObj = RealizeFontInit(hFont);
6923 DC_UnlockDc(dc);
6924 if (!TextObj)
6925 {
6926 return GDI_ERROR;
6927 }
6928
6929 FontGDI = ObjToGDI(TextObj->Font, FONT);
6930 TEXTOBJ_UnlockText(TextObj);
6931
6932 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
6933 if (!Buffer)
6934 {
6935 return GDI_ERROR;
6936 }
6937
6938 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
6939 {
6940 DefChar = 0xffff;
6941 }
6942 else
6943 {
6944 FT_Face Face = FontGDI->SharedFace->Face;
6945 if (FT_IS_SFNT(Face))
6946 {
6947 TT_OS2 *pOS2;
6948
6949 IntLockFreeType();
6950 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
6951 DefChar = (pOS2->usDefaultChar ? get_glyph_index(Face, pOS2->usDefaultChar) : 0);
6952 IntUnLockFreeType();
6953 }
6954 else
6955 {
6956 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
6957 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
6958 if (!potm)
6959 {
6960 cwc = GDI_ERROR;
6961 goto ErrorRet;
6962 }
6963 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
6964 if (Size)
6965 DefChar = potm->otmTextMetrics.tmDefaultChar;
6966 ExFreePoolWithTag(potm, GDITAG_TEXT);
6967 }
6968 }
6969
6970 pwcSize = cwc * sizeof(WCHAR);
6971 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6972
6973 if (!Safepwc)
6974 {
6975 Status = STATUS_NO_MEMORY;
6976 goto ErrorRet;
6977 }
6978
6979 _SEH2_TRY
6980 {
6981 ProbeForRead(UnSafepwc, pwcSize, 1);
6982 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6983 }
6984 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6985 {
6986 Status = _SEH2_GetExceptionCode();
6987 }
6988 _SEH2_END;
6989
6990 if (!NT_SUCCESS(Status)) goto ErrorRet;
6991
6992 IntLockFreeType();
6993
6994 for (i = 0; i < cwc; i++)
6995 {
6996 Buffer[i] = get_glyph_index(FontGDI->SharedFace->Face, Safepwc[i]);
6997 if (Buffer[i] == 0)
6998 {
6999 Buffer[i] = DefChar;
7000 }
7001 }
7002
7003 IntUnLockFreeType();
7004
7005 _SEH2_TRY
7006 {
7007 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
7008 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
7009 }
7010 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7011 {
7012 Status = _SEH2_GetExceptionCode();
7013 }
7014 _SEH2_END;
7015
7016 ErrorRet:
7017 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
7018 if (Safepwc != NULL)
7019 {
7020 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7021 }
7022 if (NT_SUCCESS(Status)) return cwc;
7023 return GDI_ERROR;
7024 }
7025
7026 /* EOF */