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