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