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