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