[FREETYPE] Fix Regression "Monospaced font in LibreOffice" CORE-15018
[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)
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 != (TM->tmPitchAndFamily & 0xF0))
4339 {
4340 /* Family Penalty 9000 */
4341 /* Requested a family, but the candidate's family is different. */
4342 Penalty += 9000;
4343 }
4344 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
4345 {
4346 /* FamilyUnknown Penalty 8000 */
4347 /* Requested a family, but the candidate has no family. */
4348 Penalty += 8000;
4349 }
4350 }
4351
4352 /* Is the candidate a non-vector font? */
4353 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4354 {
4355 /* Is lfHeight specified? */
4356 if (LogFont->lfHeight != 0)
4357 {
4358 if (labs(LogFont->lfHeight) < TM->tmHeight)
4359 {
4360 /* HeightBigger Penalty 600 */
4361 /* The candidate is a nonvector font and is bigger than the
4362 requested height. */
4363 Penalty += 600;
4364 /* HeightBiggerDifference Penalty 150 */
4365 /* The candidate is a raster font and is larger than the
4366 requested height. Penalty * height difference */
4367 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4368
4369 fNeedScaling = TRUE;
4370 }
4371 if (TM->tmHeight < labs(LogFont->lfHeight))
4372 {
4373 /* HeightSmaller Penalty 150 */
4374 /* The candidate is a raster font and is smaller than the
4375 requested height. Penalty * height difference */
4376 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4377
4378 fNeedScaling = TRUE;
4379 }
4380 }
4381 }
4382
4383 switch (LogFont->lfPitchAndFamily & 0xF0)
4384 {
4385 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4386 switch (TM->tmPitchAndFamily & 0xF0)
4387 {
4388 case FF_DECORATIVE: case FF_SCRIPT:
4389 /* FamilyUnlikely Penalty 50 */
4390 /* Requested a roman/modern/swiss family, but the
4391 candidate is decorative/script. */
4392 Penalty += 50;
4393 break;
4394 default:
4395 break;
4396 }
4397 break;
4398 case FF_DECORATIVE: case FF_SCRIPT:
4399 switch (TM->tmPitchAndFamily & 0xF0)
4400 {
4401 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4402 /* FamilyUnlikely Penalty 50 */
4403 /* Or requested decorative/script, and the candidate is
4404 roman/modern/swiss. */
4405 Penalty += 50;
4406 break;
4407 default:
4408 break;
4409 }
4410 default:
4411 break;
4412 }
4413
4414 if (LogFont->lfWidth != 0)
4415 {
4416 if (LogFont->lfWidth != TM->tmAveCharWidth)
4417 {
4418 /* Width Penalty 50 */
4419 /* Requested a nonzero width, but the candidate's width
4420 doesn't match. Penalty * width difference */
4421 Penalty += 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth);
4422
4423 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4424 fNeedScaling = TRUE;
4425 }
4426 }
4427
4428 if (fNeedScaling)
4429 {
4430 /* SizeSynth Penalty 50 */
4431 /* The candidate is a raster font that needs scaling by GDI. */
4432 Penalty += 50;
4433 }
4434
4435 if (!!LogFont->lfItalic != !!TM->tmItalic)
4436 {
4437 if (!LogFont->lfItalic && ItalicFromStyle(style_name))
4438 {
4439 /* Italic Penalty 4 */
4440 /* Requested font and candidate font do not agree on italic status,
4441 and the desired result cannot be simulated. */
4442 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
4443 Penalty += 40;
4444 }
4445 else if (LogFont->lfItalic && !ItalicFromStyle(style_name))
4446 {
4447 /* ItalicSim Penalty 1 */
4448 /* Requested italic font but the candidate is not italic,
4449 although italics can be simulated. */
4450 Penalty += 1;
4451 }
4452 }
4453
4454 if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
4455 {
4456 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
4457 {
4458 /* NotTrueType Penalty 4 */
4459 /* Requested OUT_TT_PRECIS, but the candidate is not a
4460 TrueType font. */
4461 Penalty += 4;
4462 }
4463 }
4464
4465 Long = LogFont->lfWeight;
4466 if (LogFont->lfWeight == FW_DONTCARE)
4467 Long = FW_NORMAL;
4468 if (Long != TM->tmWeight)
4469 {
4470 /* Weight Penalty 3 */
4471 /* The candidate's weight does not match the requested weight.
4472 Penalty * (weight difference/10) */
4473 Penalty += 3 * (labs(Long - TM->tmWeight) / 10);
4474 }
4475
4476 if (!LogFont->lfUnderline && TM->tmUnderlined)
4477 {
4478 /* Underline Penalty 3 */
4479 /* Requested font has no underline, but the candidate is
4480 underlined. */
4481 Penalty += 3;
4482 }
4483
4484 if (!LogFont->lfStrikeOut && TM->tmStruckOut)
4485 {
4486 /* StrikeOut Penalty 3 */
4487 /* Requested font has no strike-out, but the candidate is
4488 struck out. */
4489 Penalty += 3;
4490 }
4491
4492 /* Is the candidate a non-vector font? */
4493 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4494 {
4495 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
4496 {
4497 /* VectorHeightSmaller Penalty 2 */
4498 /* Candidate is a vector font that is smaller than the
4499 requested height. Penalty * height difference */
4500 Penalty += 2 * labs(TM->tmHeight - LogFont->lfHeight);
4501 }
4502 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
4503 {
4504 /* VectorHeightBigger Penalty 1 */
4505 /* Candidate is a vector font that is bigger than the
4506 requested height. Penalty * height difference */
4507 Penalty += 1 * labs(TM->tmHeight - LogFont->lfHeight);
4508 }
4509 }
4510
4511 if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
4512 {
4513 /* DeviceFavor Penalty 2 */
4514 /* Extra penalty for all nondevice fonts. */
4515 Penalty += 2;
4516 }
4517
4518 if (TM->tmAveCharWidth >= 5 && TM->tmHeight >= 5)
4519 {
4520 if (TM->tmAveCharWidth / TM->tmHeight >= 3)
4521 {
4522 /* Aspect Penalty 30 */
4523 /* The aspect rate is >= 3. It seems like a bad font. */
4524 Penalty += ((TM->tmAveCharWidth / TM->tmHeight) - 2) * 30;
4525 }
4526 else if (TM->tmHeight / TM->tmAveCharWidth >= 3)
4527 {
4528 /* Aspect Penalty 30 */
4529 /* The aspect rate is >= 3. It seems like a bad font. */
4530 Penalty += ((TM->tmHeight / TM->tmAveCharWidth) - 2) * 30;
4531 }
4532 }
4533
4534 if (Penalty < 200)
4535 {
4536 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
4537 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
4538 "tmCharSet:%d, tmWeight:%ld\n",
4539 Penalty, LogFont->lfFaceName, ActualNameW,
4540 LogFont->lfCharSet, LogFont->lfWeight,
4541 TM->tmCharSet, TM->tmWeight);
4542 }
4543
4544 return Penalty; /* success */
4545 }
4546
4547 static __inline VOID
4548 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
4549 const LOGFONTW *LogFont,
4550 const PLIST_ENTRY Head)
4551 {
4552 ULONG Penalty;
4553 PLIST_ENTRY Entry;
4554 PFONT_ENTRY CurrentEntry;
4555 FONTGDI *FontGDI;
4556 OUTLINETEXTMETRICW *Otm = NULL;
4557 UINT OtmSize, OldOtmSize = 0;
4558 FT_Face Face;
4559
4560 ASSERT(FontObj);
4561 ASSERT(MatchPenalty);
4562 ASSERT(LogFont);
4563 ASSERT(Head);
4564
4565 /* Start with a pretty big buffer */
4566 OldOtmSize = 0x200;
4567 Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
4568
4569 /* get the FontObj of lowest penalty */
4570 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
4571 {
4572 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
4573
4574 FontGDI = CurrentEntry->Font;
4575 ASSERT(FontGDI);
4576 Face = FontGDI->SharedFace->Face;
4577
4578 /* get text metrics */
4579 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4580 if (OtmSize > OldOtmSize)
4581 {
4582 if (Otm)
4583 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4584 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
4585 }
4586
4587 /* update FontObj if lowest penalty */
4588 if (Otm)
4589 {
4590 IntLockFreeType();
4591 IntRequestFontSize(NULL, FontGDI, LogFont->lfWidth, LogFont->lfHeight);
4592 IntUnLockFreeType();
4593
4594 OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
4595 if (!OtmSize)
4596 continue;
4597
4598 OldOtmSize = OtmSize;
4599
4600 Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
4601 if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
4602 {
4603 *FontObj = GDIToObj(FontGDI, FONT);
4604 *MatchPenalty = Penalty;
4605 }
4606 }
4607 }
4608
4609 if (Otm)
4610 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4611 }
4612
4613 static
4614 VOID
4615 FASTCALL
4616 IntFontType(PFONTGDI Font)
4617 {
4618 PS_FontInfoRec psfInfo;
4619 FT_ULong tmp_size = 0;
4620 FT_Face Face = Font->SharedFace->Face;
4621
4622 if (FT_HAS_MULTIPLE_MASTERS(Face))
4623 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
4624 if (FT_HAS_VERTICAL(Face))
4625 Font->FontObj.flFontType |= FO_VERT_FACE;
4626 if (!FT_IS_SCALABLE(Face))
4627 Font->FontObj.flFontType |= FO_TYPE_RASTER;
4628 if (FT_IS_SFNT(Face))
4629 {
4630 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
4631 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
4632 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4633 }
4634 if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
4635 {
4636 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4637 }
4638 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
4639 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
4640 {
4641 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
4642 }
4643 }
4644
4645 static BOOL
4646 MatchFontName(PSHARED_FACE SharedFace, LPCWSTR lfFaceName, FT_UShort NameID, FT_UShort LangID)
4647 {
4648 NTSTATUS Status;
4649 UNICODE_STRING Name1, Name2;
4650
4651 if (lfFaceName[0] == UNICODE_NULL)
4652 return FALSE;
4653
4654 RtlInitUnicodeString(&Name1, lfFaceName);
4655
4656 RtlInitUnicodeString(&Name2, NULL);
4657 Status = IntGetFontLocalizedName(&Name2, SharedFace, NameID, LangID);
4658
4659 if (NT_SUCCESS(Status))
4660 {
4661 if (RtlCompareUnicodeString(&Name1, &Name2, TRUE) == 0)
4662 {
4663 RtlFreeUnicodeString(&Name2);
4664 return TRUE;
4665 }
4666
4667 RtlFreeUnicodeString(&Name2);
4668 }
4669
4670 return FALSE;
4671 }
4672
4673 static BOOL
4674 MatchFontNames(PSHARED_FACE SharedFace, LPCWSTR lfFaceName)
4675 {
4676 if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, LANG_ENGLISH) ||
4677 MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, LANG_ENGLISH))
4678 {
4679 return TRUE;
4680 }
4681 if (PRIMARYLANGID(gusLanguageID) != LANG_ENGLISH)
4682 {
4683 if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, gusLanguageID) ||
4684 MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, gusLanguageID))
4685 {
4686 return TRUE;
4687 }
4688 }
4689 return FALSE;
4690 }
4691
4692 NTSTATUS
4693 FASTCALL
4694 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
4695 {
4696 NTSTATUS Status = STATUS_SUCCESS;
4697 PTEXTOBJ TextObj;
4698 PPROCESSINFO Win32Process;
4699 ULONG MatchPenalty;
4700 LOGFONTW *pLogFont;
4701 LOGFONTW SubstitutedLogFont;
4702 FT_Face Face;
4703
4704 if (!pTextObj)
4705 {
4706 TextObj = TEXTOBJ_LockText(FontHandle);
4707 if (NULL == TextObj)
4708 {
4709 return STATUS_INVALID_HANDLE;
4710 }
4711
4712 if (TextObj->fl & TEXTOBJECT_INIT)
4713 {
4714 TEXTOBJ_UnlockText(TextObj);
4715 return STATUS_SUCCESS;
4716 }
4717 }
4718 else
4719 {
4720 TextObj = pTextObj;
4721 }
4722
4723 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4724
4725 /* substitute */
4726 SubstitutedLogFont = *pLogFont;
4727 DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
4728 SubstituteFontRecurse(&SubstitutedLogFont);
4729 DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
4730
4731 MatchPenalty = 0xFFFFFFFF;
4732 TextObj->Font = NULL;
4733
4734 Win32Process = PsGetCurrentProcessWin32Process();
4735
4736 /* Search private fonts */
4737 IntLockProcessPrivateFonts(Win32Process);
4738 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4739 &Win32Process->PrivateFontListHead);
4740 IntUnLockProcessPrivateFonts(Win32Process);
4741
4742 /* Search system fonts */
4743 IntLockGlobalFonts();
4744 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4745 &g_FontListHead);
4746 IntUnLockGlobalFonts();
4747
4748 if (NULL == TextObj->Font)
4749 {
4750 DPRINT1("Request font %S not found, no fonts loaded at all\n",
4751 pLogFont->lfFaceName);
4752 Status = STATUS_NOT_FOUND;
4753 }
4754 else
4755 {
4756 UNICODE_STRING Name;
4757 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
4758 PSHARED_FACE SharedFace = FontGdi->SharedFace;
4759
4760 IntLockFreeType();
4761 IntRequestFontSize(NULL, FontGdi, pLogFont->lfWidth, pLogFont->lfHeight);
4762 IntUnLockFreeType();
4763
4764 TextObj->TextFace[0] = UNICODE_NULL;
4765 if (MatchFontNames(SharedFace, SubstitutedLogFont.lfFaceName))
4766 {
4767 RtlStringCchCopyW(TextObj->TextFace, _countof(TextObj->TextFace), pLogFont->lfFaceName);
4768 }
4769 else
4770 {
4771 RtlInitUnicodeString(&Name, NULL);
4772 Status = IntGetFontLocalizedName(&Name, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
4773 if (NT_SUCCESS(Status))
4774 {
4775 /* truncated copy */
4776 Name.Length = (USHORT)min(Name.Length, (LF_FACESIZE - 1) * sizeof(WCHAR));
4777 RtlStringCbCopyNW(TextObj->TextFace, Name.Length + sizeof(WCHAR), Name.Buffer, Name.Length);
4778
4779 RtlFreeUnicodeString(&Name);
4780 }
4781 }
4782
4783 // Need hdev, when freetype is loaded need to create DEVOBJ for
4784 // Consumer and Producer.
4785 TextObj->Font->iUniq = 1; // Now it can be cached.
4786 IntFontType(FontGdi);
4787 FontGdi->flType = TextObj->Font->flFontType;
4788 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
4789 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
4790 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
4791 if (pLogFont->lfWeight != FW_DONTCARE)
4792 FontGdi->RequestWeight = pLogFont->lfWeight;
4793 else
4794 FontGdi->RequestWeight = FW_NORMAL;
4795
4796 Face = FontGdi->SharedFace->Face;
4797
4798 //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name);
4799
4800 if (!FontGdi->OriginalItalic)
4801 FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name);
4802
4803 TextObj->fl |= TEXTOBJECT_INIT;
4804 Status = STATUS_SUCCESS;
4805 }
4806
4807 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
4808
4809 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
4810
4811 return Status;
4812 }
4813
4814
4815 static
4816 BOOL
4817 FASTCALL
4818 IntGetFullFileName(
4819 POBJECT_NAME_INFORMATION NameInfo,
4820 ULONG Size,
4821 PUNICODE_STRING FileName)
4822 {
4823 NTSTATUS Status;
4824 OBJECT_ATTRIBUTES ObjectAttributes;
4825 HANDLE hFile;
4826 IO_STATUS_BLOCK IoStatusBlock;
4827 ULONG Desired;
4828
4829 InitializeObjectAttributes(&ObjectAttributes,
4830 FileName,
4831 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
4832 NULL,
4833 NULL);
4834
4835 Status = ZwOpenFile(
4836 &hFile,
4837 0, // FILE_READ_ATTRIBUTES,
4838 &ObjectAttributes,
4839 &IoStatusBlock,
4840 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4841 0);
4842
4843 if (!NT_SUCCESS(Status))
4844 {
4845 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
4846 return FALSE;
4847 }
4848
4849 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
4850 ZwClose(hFile);
4851 if (!NT_SUCCESS(Status))
4852 {
4853 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
4854 return FALSE;
4855 }
4856
4857 return TRUE;
4858 }
4859
4860 static BOOL
4861 EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2)
4862 {
4863 const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
4864 const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
4865 const LOGFONTW *plf1 = &pLog1->elfLogFont;
4866 const LOGFONTW *plf2 = &pLog2->elfLogFont;
4867
4868 if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0)
4869 {
4870 return FALSE;
4871 }
4872
4873 if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0)
4874 {
4875 return FALSE;
4876 }
4877
4878 return TRUE;
4879 }
4880
4881 static VOID
4882 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
4883 {
4884 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
4885 if (FamInfo->EnumLogFontEx.elfStyle[0] &&
4886 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
4887 {
4888 wcscat(psz, L" ");
4889 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
4890 }
4891 }
4892
4893 BOOL
4894 FASTCALL
4895 IntGdiGetFontResourceInfo(
4896 PUNICODE_STRING FileName,
4897 PVOID pBuffer,
4898 DWORD *pdwBytes,
4899 DWORD dwType)
4900 {
4901 UNICODE_STRING EntryFileName;
4902 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
4903 PLIST_ENTRY ListEntry;
4904 PFONT_ENTRY FontEntry;
4905 ULONG Size, i, Count;
4906 LPBYTE pbBuffer;
4907 BOOL IsEqual;
4908 FONTFAMILYINFO *FamInfo;
4909 const ULONG MaxFamInfo = 64;
4910 BOOL bSuccess;
4911
4912 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
4913
4914 /* Create buffer for full path name */
4915 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
4916 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4917 if (!NameInfo1)
4918 {
4919 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4920 return FALSE;
4921 }
4922
4923 /* Get the full path name */
4924 if (!IntGetFullFileName(NameInfo1, Size, FileName))
4925 {
4926 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4927 return FALSE;
4928 }
4929
4930 /* Create a buffer for the entries' names */
4931 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4932 if (!NameInfo2)
4933 {
4934 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4935 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4936 return FALSE;
4937 }
4938
4939 FamInfo = ExAllocatePoolWithTag(PagedPool,
4940 sizeof(FONTFAMILYINFO) * MaxFamInfo,
4941 TAG_FINF);
4942 if (!FamInfo)
4943 {
4944 ExFreePoolWithTag(NameInfo2, TAG_FINF);
4945 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4946 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4947 return FALSE;
4948 }
4949 /* Try to find the pathname in the global font list */
4950 Count = 0;
4951 IntLockGlobalFonts();
4952 for (ListEntry = g_FontListHead.Flink; ListEntry != &g_FontListHead;
4953 ListEntry = ListEntry->Flink)
4954 {
4955 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
4956 if (FontEntry->Font->Filename == NULL)
4957 continue;
4958
4959 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
4960 if (!IntGetFullFileName(NameInfo2, Size, &EntryFileName))
4961 continue;
4962
4963 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
4964 continue;
4965
4966 IsEqual = FALSE;
4967 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
4968 NULL, FontEntry->Font);
4969 for (i = 0; i < Count; ++i)
4970 {
4971 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
4972 {
4973 IsEqual = TRUE;
4974 break;
4975 }
4976 }
4977 if (!IsEqual)
4978 {
4979 /* Found */
4980 ++Count;
4981 if (Count >= MaxFamInfo)
4982 break;
4983 }
4984 }
4985 IntUnLockGlobalFonts();
4986
4987 /* Free the buffers */
4988 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4989 ExFreePool(NameInfo2);
4990
4991 if (Count == 0 && dwType != 5)
4992 {
4993 /* Font could not be found in system table
4994 dwType == 5 will still handle this */
4995 ExFreePoolWithTag(FamInfo, TAG_FINF);
4996 return FALSE;
4997 }
4998
4999 bSuccess = FALSE;
5000 switch (dwType)
5001 {
5002 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
5003 Size = sizeof(DWORD);
5004 if (*pdwBytes == 0)
5005 {
5006 *pdwBytes = Size;
5007 bSuccess = TRUE;
5008 }
5009 else if (pBuffer)
5010 {
5011 if (*pdwBytes >= Size)
5012 {
5013 *(DWORD*)pBuffer = Count;
5014 }
5015 *pdwBytes = Size;
5016 bSuccess = TRUE;
5017 }
5018 break;
5019
5020 case 1: /* copy the font title */
5021 /* calculate the required size */
5022 Size = 0;
5023 Size += wcslen(FamInfo[0].EnumLogFontEx.elfLogFont.lfFaceName);
5024 if (FamInfo[0].EnumLogFontEx.elfStyle[0] &&
5025 _wcsicmp(FamInfo[0].EnumLogFontEx.elfStyle, L"Regular") != 0)
5026 {
5027 Size += 1 + wcslen(FamInfo[0].EnumLogFontEx.elfStyle);
5028 }
5029 for (i = 1; i < Count; ++i)
5030 {
5031 Size += 3; /* " & " */
5032 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
5033 if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
5034 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
5035 {
5036 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
5037 }
5038 }
5039 Size += 2; /* "\0\0" */
5040 Size *= sizeof(WCHAR);
5041
5042 if (*pdwBytes == 0)
5043 {
5044 *pdwBytes = Size;
5045 bSuccess = TRUE;
5046 }
5047 else if (pBuffer)
5048 {
5049 if (*pdwBytes >= Size)
5050 {
5051 /* store font title to buffer */
5052 WCHAR *psz = pBuffer;
5053 *psz = 0;
5054 IntAddNameFromFamInfo(psz, &FamInfo[0]);
5055 for (i = 1; i < Count; ++i)
5056 {
5057 wcscat(psz, L" & ");
5058 IntAddNameFromFamInfo(psz, &FamInfo[i]);
5059 }
5060 psz[wcslen(psz) + 1] = UNICODE_NULL;
5061 *pdwBytes = Size;
5062 bSuccess = TRUE;
5063 }
5064 else
5065 {
5066 *pdwBytes = 1024; /* this is confirmed value */
5067 }
5068 }
5069 break;
5070
5071 case 2: /* Copy an array of LOGFONTW */
5072 Size = Count * sizeof(LOGFONTW);
5073 if (*pdwBytes == 0)
5074 {
5075 *pdwBytes = Size;
5076 bSuccess = TRUE;
5077 }
5078 else if (pBuffer)
5079 {
5080 if (*pdwBytes >= Size)
5081 {
5082 pbBuffer = (LPBYTE)pBuffer;
5083 for (i = 0; i < Count; ++i)
5084 {
5085 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
5086 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
5087 pbBuffer += sizeof(LOGFONTW);
5088 }
5089 }
5090 *pdwBytes = Size;
5091 bSuccess = TRUE;
5092 }
5093 else
5094 {
5095 *pdwBytes = 1024; /* this is confirmed value */
5096 }
5097 break;
5098
5099 case 3:
5100 Size = sizeof(DWORD);
5101 if (*pdwBytes == 0)
5102 {
5103 *pdwBytes = Size;
5104 bSuccess = TRUE;
5105 }
5106 else if (pBuffer)
5107 {
5108 if (*pdwBytes >= Size)
5109 {
5110 /* FIXME: What exactly is copied here? */
5111 *(DWORD*)pBuffer = 1;
5112 }
5113 *pdwBytes = Size;
5114 bSuccess = TRUE;
5115 }
5116 break;
5117
5118 case 4: /* full file path */
5119 if (FileName->Length >= 4 * sizeof(WCHAR))
5120 {
5121 /* The beginning of FileName is \??\ */
5122 LPWSTR pch = FileName->Buffer + 4;
5123 DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
5124
5125 Size = Length + sizeof(WCHAR);
5126 if (*pdwBytes == 0)
5127 {
5128 *pdwBytes = Size;
5129 bSuccess = TRUE;
5130 }
5131 else if (pBuffer)
5132 {
5133 if (*pdwBytes >= Size)
5134 {
5135 RtlCopyMemory(pBuffer, pch, Size);
5136 }
5137 *pdwBytes = Size;
5138 bSuccess = TRUE;
5139 }
5140 }
5141 break;
5142
5143 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
5144 Size = sizeof(BOOL);
5145 if (*pdwBytes == 0)
5146 {
5147 *pdwBytes = Size;
5148 bSuccess = TRUE;
5149 }
5150 else if (pBuffer)
5151 {
5152 if (*pdwBytes >= Size)
5153 {
5154 *(BOOL*)pBuffer = Count == 0;
5155 }
5156 *pdwBytes = Size;
5157 bSuccess = TRUE;
5158 }
5159 break;
5160 }
5161 ExFreePoolWithTag(FamInfo, TAG_FINF);
5162
5163 return bSuccess;
5164 }
5165
5166
5167 BOOL
5168 FASTCALL
5169 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
5170 {
5171 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
5172 Info->iTechnology = RI_TECH_BITMAP;
5173 else
5174 {
5175 if (FT_IS_SCALABLE(Font->SharedFace->Face))
5176 Info->iTechnology = RI_TECH_SCALABLE;
5177 else
5178 Info->iTechnology = RI_TECH_FIXED;
5179 }
5180 Info->iUniq = Font->FontObj.iUniq;
5181 Info->dwUnknown = -1;
5182 return TRUE;
5183 }
5184
5185
5186 DWORD
5187 FASTCALL
5188 ftGdiGetKerningPairs( PFONTGDI Font,
5189 DWORD cPairs,
5190 LPKERNINGPAIR pKerningPair)
5191 {
5192 DWORD Count = 0;
5193 INT i = 0;
5194 FT_Face face = Font->SharedFace->Face;
5195
5196 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
5197 {
5198 FT_UInt previous_index = 0, glyph_index = 0;
5199 FT_ULong char_code, char_previous;
5200 FT_Vector delta;
5201
5202 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
5203
5204 IntLockFreeType();
5205
5206 while (glyph_index)
5207 {
5208 if (previous_index && glyph_index)
5209 {
5210 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
5211
5212 if (pKerningPair && cPairs)
5213 {
5214 pKerningPair[i].wFirst = char_previous;
5215 pKerningPair[i].wSecond = char_code;
5216 pKerningPair[i].iKernAmount = delta.x;
5217 i++;
5218 if (i == cPairs) break;
5219 }
5220 Count++;
5221 }
5222 previous_index = glyph_index;
5223 char_previous = char_code;
5224 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
5225 }
5226 IntUnLockFreeType();
5227 }
5228 return Count;
5229 }
5230
5231
5232 ///////////////////////////////////////////////////////////////////////////
5233 //
5234 // Functions needing sorting.
5235 //
5236 ///////////////////////////////////////////////////////////////////////////
5237 int APIENTRY
5238 NtGdiGetFontFamilyInfo(HDC Dc,
5239 LPLOGFONTW UnsafeLogFont,
5240 PFONTFAMILYINFO UnsafeInfo,
5241 DWORD Size)
5242 {
5243 NTSTATUS Status;
5244 LOGFONTW LogFont;
5245 PFONTFAMILYINFO Info;
5246 DWORD Count;
5247 PPROCESSINFO Win32Process;
5248
5249 /* Make a safe copy */
5250 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
5251 if (! NT_SUCCESS(Status))
5252 {
5253 EngSetLastError(ERROR_INVALID_PARAMETER);
5254 return -1;
5255 }
5256
5257 /* Allocate space for a safe copy */
5258 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT);
5259 if (NULL == Info)
5260 {
5261 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5262 return -1;
5263 }
5264
5265 /* Enumerate font families in the global list */
5266 IntLockGlobalFonts();
5267 Count = 0;
5268 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &g_FontListHead) )
5269 {
5270 IntUnLockGlobalFonts();
5271 ExFreePoolWithTag(Info, GDITAG_TEXT);
5272 return -1;
5273 }
5274 IntUnLockGlobalFonts();
5275
5276 /* Enumerate font families in the process local list */
5277 Win32Process = PsGetCurrentProcessWin32Process();
5278 IntLockProcessPrivateFonts(Win32Process);
5279 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
5280 &Win32Process->PrivateFontListHead))
5281 {
5282 IntUnLockProcessPrivateFonts(Win32Process);
5283 ExFreePoolWithTag(Info, GDITAG_TEXT);
5284 return -1;
5285 }
5286 IntUnLockProcessPrivateFonts(Win32Process);
5287
5288 /* Enumerate font families in the registry */
5289 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
5290 {
5291 ExFreePoolWithTag(Info, GDITAG_TEXT);
5292 return -1;
5293 }
5294
5295 /* Return data to caller */
5296 if (0 != Count)
5297 {
5298 Status = MmCopyToCaller(UnsafeInfo, Info,
5299 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
5300 if (! NT_SUCCESS(Status))
5301 {
5302 ExFreePoolWithTag(Info, GDITAG_TEXT);
5303 EngSetLastError(ERROR_INVALID_PARAMETER);
5304 return -1;
5305 }
5306 }
5307
5308 ExFreePoolWithTag(Info, GDITAG_TEXT);
5309
5310 return Count;
5311 }
5312
5313 FORCEINLINE
5314 LONG
5315 ScaleLong(LONG lValue, PFLOATOBJ pef)
5316 {
5317 FLOATOBJ efTemp;
5318
5319 /* Check if we have scaling different from 1 */
5320 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
5321 {
5322 /* Need to multiply */
5323 FLOATOBJ_SetLong(&efTemp, lValue);
5324 FLOATOBJ_Mul(&efTemp, pef);
5325 lValue = FLOATOBJ_GetLong(&efTemp);
5326 }
5327
5328 return lValue;
5329 }
5330
5331 BOOL
5332 APIENTRY
5333 GreExtTextOutW(
5334 IN HDC hDC,
5335 IN INT XStart,
5336 IN INT YStart,
5337 IN UINT fuOptions,
5338 IN OPTIONAL PRECTL lprc,
5339 IN LPCWSTR String,
5340 IN INT Count,
5341 IN OPTIONAL LPINT Dx,
5342 IN DWORD dwCodePage)
5343 {
5344 /*
5345 * FIXME:
5346 * Call EngTextOut, which does the real work (calling DrvTextOut where
5347 * appropriate)
5348 */
5349
5350 DC *dc;
5351 PDC_ATTR pdcattr;
5352 SURFOBJ *SurfObj;
5353 SURFACE *psurf = NULL;
5354 int error, glyph_index, i;
5355 FT_Face face;
5356 FT_GlyphSlot glyph;
5357 FT_BitmapGlyph realglyph;
5358 LONGLONG TextLeft, RealXStart;
5359 ULONG TextTop, previous, BackgroundLeft;
5360 FT_Bool use_kerning;
5361 RECTL DestRect, MaskRect;
5362 POINTL SourcePoint, BrushOrigin;
5363 HBITMAP HSourceGlyph;
5364 SURFOBJ *SourceGlyphSurf;
5365 SIZEL bitSize;
5366 INT yoff;
5367 FONTOBJ *FontObj;
5368 PFONTGDI FontGDI;
5369 PTEXTOBJ TextObj = NULL;
5370 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
5371 FT_Render_Mode RenderMode;
5372 BOOLEAN Render;
5373 POINT Start;
5374 BOOL DoBreak = FALSE;
5375 USHORT DxShift;
5376 PMATRIX pmxWorldToDevice;
5377 LONG fixAscender, fixDescender;
5378 FLOATOBJ Scale;
5379 LOGFONTW *plf;
5380 BOOL EmuBold, EmuItalic;
5381 int thickness;
5382 BOOL bResult;
5383
5384 /* Check if String is valid */
5385 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
5386 {
5387 EngSetLastError(ERROR_INVALID_PARAMETER);
5388 return FALSE;
5389 }
5390
5391 /* NOTE: This function locks the screen DC, so it must never be called
5392 with a DC already locked */
5393 Render = IntIsFontRenderingEnabled();
5394
5395 // TODO: Write test-cases to exactly match real Windows in different
5396 // bad parameters (e.g. does Windows check the DC or the RECT first?).
5397 dc = DC_LockDc(hDC);
5398 if (!dc)
5399 {
5400 EngSetLastError(ERROR_INVALID_HANDLE);
5401 return FALSE;
5402 }
5403
5404 if (PATH_IsPathOpen(dc->dclevel))
5405 {
5406 bResult = PATH_ExtTextOut(dc,
5407 XStart,
5408 YStart,
5409 fuOptions,
5410 (const RECTL *)lprc,
5411 String,
5412 Count,
5413 (const INT *)Dx);
5414 DC_UnlockDc(dc);
5415 return bResult;
5416 }
5417
5418 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
5419
5420 if (!dc->dclevel.pSurface)
5421 {
5422 /* Memory DC with no surface selected */
5423 bResult = TRUE;
5424 goto Cleanup;
5425 }
5426
5427 pdcattr = dc->pdcattr;
5428
5429 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
5430 {
5431 IntLPtoDP(dc, (POINT *)lprc, 2);
5432 }
5433
5434 if (pdcattr->lTextAlign & TA_UPDATECP)
5435 {
5436 Start.x = pdcattr->ptlCurrent.x;
5437 Start.y = pdcattr->ptlCurrent.y;
5438 } else {
5439 Start.x = XStart;
5440 Start.y = YStart;
5441 }
5442
5443 IntLPtoDP(dc, &Start, 1);
5444 RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
5445 YStart = Start.y + dc->ptlDCOrig.y;
5446
5447 SourcePoint.x = 0;
5448 SourcePoint.y = 0;
5449 MaskRect.left = 0;
5450 MaskRect.top = 0;
5451 BrushOrigin.x = 0;
5452 BrushOrigin.y = 0;
5453
5454 if ((fuOptions & ETO_OPAQUE) && lprc)
5455 {
5456 DestRect.left = lprc->left;
5457 DestRect.top = lprc->top;
5458 DestRect.right = lprc->right;
5459 DestRect.bottom = lprc->bottom;
5460
5461 DestRect.left += dc->ptlDCOrig.x;
5462 DestRect.top += dc->ptlDCOrig.y;
5463 DestRect.right += dc->ptlDCOrig.x;
5464 DestRect.bottom += dc->ptlDCOrig.y;
5465
5466 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5467 {
5468 IntUpdateBoundsRect(dc, &DestRect);
5469 }
5470
5471 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5472 DC_vUpdateBackgroundBrush(dc);
5473 if (dc->dctype == DCTYPE_DIRECT)
5474 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5475
5476 psurf = dc->dclevel.pSurface;
5477 IntEngBitBlt(
5478 &psurf->SurfObj,
5479 NULL,
5480 NULL,
5481 (CLIPOBJ *)&dc->co,
5482 NULL,
5483 &DestRect,
5484 &SourcePoint,
5485 &SourcePoint,
5486 &dc->eboBackground.BrushObject,
5487 &BrushOrigin,
5488 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5489
5490 if (dc->dctype == DCTYPE_DIRECT)
5491 MouseSafetyOnDrawEnd(dc->ppdev);
5492
5493 fuOptions &= ~ETO_OPAQUE;
5494 }
5495 else
5496 {
5497 if (pdcattr->jBkMode == OPAQUE)
5498 {
5499 fuOptions |= ETO_OPAQUE;
5500 }
5501 }
5502
5503 TextObj = RealizeFontInit(pdcattr->hlfntNew);
5504 if (TextObj == NULL)
5505 {
5506 bResult = FALSE;
5507 goto Cleanup;
5508 }
5509
5510 FontObj = TextObj->Font;
5511 ASSERT(FontObj);
5512 FontGDI = ObjToGDI(FontObj, FONT);
5513 ASSERT(FontGDI);
5514
5515 IntLockFreeType();
5516 face = FontGDI->SharedFace->Face;
5517
5518 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5519 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
5520 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
5521
5522 if (Render)
5523 RenderMode = IntGetFontRenderMode(plf);
5524 else
5525 RenderMode = FT_RENDER_MODE_MONO;
5526
5527 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
5528 {
5529 IntUnLockFreeType();
5530 bResult = FALSE;
5531 goto Cleanup;
5532 }
5533
5534 /* NOTE: Don't trust face->size->metrics.ascender and descender values. */
5535 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
5536 {
5537 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
5538 FtSetCoordinateTransform(face, pmxWorldToDevice);
5539
5540 fixAscender = ScaleLong(FontGDI->tmAscent, &pmxWorldToDevice->efM22) << 6;
5541 fixDescender = ScaleLong(FontGDI->tmDescent, &pmxWorldToDevice->efM22) << 6;
5542 }
5543 else
5544 {
5545 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
5546 FtSetCoordinateTransform(face, pmxWorldToDevice);
5547
5548 fixAscender = FontGDI->tmAscent << 6;
5549 fixDescender = FontGDI->tmDescent << 6;
5550 }
5551
5552 /*
5553 * Process the vertical alignment and determine the yoff.
5554 */
5555 #define VALIGN_MASK (TA_TOP | TA_BASELINE | TA_BOTTOM)
5556 if ((pdcattr->lTextAlign & VALIGN_MASK) == TA_BASELINE)
5557 yoff = 0;
5558 else if ((pdcattr->lTextAlign & VALIGN_MASK) == TA_BOTTOM)
5559 yoff = -(fixDescender >> 6);
5560 else /* TA_TOP */
5561 yoff = fixAscender >> 6;
5562 #undef VALIGN_MASK
5563
5564 use_kerning = FT_HAS_KERNING(face);
5565 previous = 0;
5566
5567 /*
5568 * Process the horizontal alignment and modify XStart accordingly.
5569 */
5570 DxShift = fuOptions & ETO_PDY ? 1 : 0;
5571 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
5572 {
5573 ULONGLONG TextWidth = 0;
5574 LPCWSTR TempText = String;
5575 int iStart;
5576
5577 /*
5578 * Calculate width of the text.
5579 */
5580
5581 if (NULL != Dx)
5582 {
5583 iStart = Count < 2 ? 0 : Count - 2;
5584 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
5585 }
5586 else
5587 {
5588 iStart = 0;
5589 }
5590 TempText = String + iStart;
5591
5592 for (i = iStart; i < Count; i++)
5593 {
5594 glyph_index = get_glyph_index_flagged(face, *TempText, ETO_GLYPH_INDEX, fuOptions);
5595
5596 if (EmuBold || EmuItalic)
5597 realglyph = NULL;
5598 else
5599 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
5600 RenderMode, pmxWorldToDevice);
5601 if (!realglyph)
5602 {
5603 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5604 if (error)
5605 {
5606 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
5607 }
5608
5609 glyph = face->glyph;
5610 if (EmuBold || EmuItalic)
5611 {
5612 if (EmuBold)
5613 FT_GlyphSlot_Embolden(glyph);
5614 if (EmuItalic)
5615 FT_GlyphSlot_Oblique(glyph);
5616 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5617 }
5618 else
5619 {
5620 realglyph = ftGdiGlyphCacheSet(face,
5621 glyph_index,
5622 plf->lfHeight,
5623 pmxWorldToDevice,
5624 glyph,
5625 RenderMode);
5626 }
5627 if (!realglyph)
5628 {
5629 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5630 IntUnLockFreeType();
5631 goto Cleanup;
5632 }
5633
5634 }
5635 /* Retrieve kerning distance */
5636 if (use_kerning && previous && glyph_index)
5637 {
5638 FT_Vector delta;
5639 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5640 TextWidth += delta.x;
5641 }
5642
5643 TextWidth += realglyph->root.advance.x >> 10;
5644
5645 if (EmuBold || EmuItalic)
5646 {
5647 FT_Done_Glyph((FT_Glyph)realglyph);
5648 realglyph = NULL;
5649 }
5650
5651 previous = glyph_index;
5652 TempText++;
5653 }
5654
5655 previous = 0;
5656
5657 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
5658 {
5659 RealXStart -= TextWidth / 2;
5660 }
5661 else
5662 {
5663 RealXStart -= TextWidth;
5664 }
5665 }
5666
5667 psurf = dc->dclevel.pSurface;
5668 SurfObj = &psurf->SurfObj ;
5669
5670 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
5671 DC_vUpdateBackgroundBrush(dc) ;
5672
5673 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
5674 DC_vUpdateTextBrush(dc) ;
5675
5676 if (!face->units_per_EM)
5677 {
5678 thickness = 1;
5679 }
5680 else
5681 {
5682 thickness = face->underline_thickness *
5683 face->size->metrics.y_ppem / face->units_per_EM;
5684 if (thickness <= 0)
5685 thickness = 1;
5686 }
5687
5688 if ((fuOptions & ETO_OPAQUE) && plf->lfItalic)
5689 {
5690 /* Draw background */
5691 TextLeft = RealXStart;
5692 TextTop = YStart;
5693 BackgroundLeft = (RealXStart + 32) >> 6;
5694 for (i = 0; i < Count; ++i)
5695 {
5696 glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions);
5697
5698 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5699 if (error)
5700 {
5701 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5702 IntUnLockFreeType();
5703 goto Cleanup;
5704 }
5705
5706 glyph = face->glyph;
5707 if (EmuBold)
5708 FT_GlyphSlot_Embolden(glyph);
5709 if (EmuItalic)
5710 FT_GlyphSlot_Oblique(glyph);
5711 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5712 if (!realglyph)
5713 {
5714 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5715 IntUnLockFreeType();
5716 goto Cleanup;
5717 }
5718
5719 /* retrieve kerning distance and move pen position */
5720 if (use_kerning && previous && glyph_index && NULL == Dx)
5721 {
5722 FT_Vector delta;
5723 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5724 TextLeft += delta.x;
5725 }
5726 DPRINT("TextLeft: %I64d\n", TextLeft);
5727 DPRINT("TextTop: %lu\n", TextTop);
5728 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5729
5730 DestRect.left = BackgroundLeft;
5731 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5732 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5733 DestRect.bottom = DestRect.top + ((fixAscender + fixDescender) >> 6);
5734 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5735 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5736 {
5737 IntUpdateBoundsRect(dc, &DestRect);
5738 }
5739 IntEngBitBlt(
5740 &psurf->SurfObj,
5741 NULL,
5742 NULL,
5743 (CLIPOBJ *)&dc->co,
5744 NULL,
5745 &DestRect,
5746 &SourcePoint,
5747 &SourcePoint,
5748 &dc->eboBackground.BrushObject,
5749 &BrushOrigin,
5750 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5751 MouseSafetyOnDrawEnd(dc->ppdev);
5752 BackgroundLeft = DestRect.right;
5753
5754 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5755 DestRect.right = DestRect.left + realglyph->bitmap.width;
5756 DestRect.top = TextTop + yoff - realglyph->top;
5757 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5758
5759 bitSize.cx = realglyph->bitmap.width;
5760 bitSize.cy = realglyph->bitmap.rows;
5761 MaskRect.right = realglyph->bitmap.width;
5762 MaskRect.bottom = realglyph->bitmap.rows;
5763
5764 if (NULL == Dx)
5765 {
5766 TextLeft += realglyph->root.advance.x >> 10;
5767 DPRINT("New TextLeft: %I64d\n", TextLeft);
5768 }
5769 else
5770 {
5771 // FIXME this should probably be a matrix transform with TextTop as well.
5772 Scale = pdcattr->mxWorldToDevice.efM11;
5773 if (FLOATOBJ_Equal0(&Scale))
5774 FLOATOBJ_Set1(&Scale);
5775
5776 /* do the shift before multiplying to preserve precision */
5777 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5778 TextLeft += FLOATOBJ_GetLong(&Scale);
5779 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5780 }
5781
5782 if (DxShift)
5783 {
5784 TextTop -= Dx[2 * i + 1] << 6;
5785 }
5786
5787 previous = glyph_index;
5788
5789 if (EmuBold || EmuItalic)
5790 {
5791 FT_Done_Glyph((FT_Glyph)realglyph);
5792 realglyph = NULL;
5793 }
5794 }
5795 }
5796
5797 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
5798 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
5799
5800 /* Assume success */
5801 bResult = TRUE;
5802
5803 /*
5804 * The main rendering loop.
5805 */
5806 TextLeft = RealXStart;
5807 TextTop = YStart;
5808 BackgroundLeft = (RealXStart + 32) >> 6;
5809 for (i = 0; i < Count; ++i)
5810 {
5811 glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions);
5812
5813 if (EmuBold || EmuItalic)
5814 realglyph = NULL;
5815 else
5816 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
5817 RenderMode, pmxWorldToDevice);
5818 if (!realglyph)
5819 {
5820 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5821 if (error)
5822 {
5823 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5824 bResult = FALSE;
5825 break;
5826 }
5827
5828 glyph = face->glyph;
5829 if (EmuBold || EmuItalic)
5830 {
5831 if (EmuBold)
5832 FT_GlyphSlot_Embolden(glyph);
5833 if (EmuItalic)
5834 FT_GlyphSlot_Oblique(glyph);
5835 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5836 }
5837 else
5838 {
5839 realglyph = ftGdiGlyphCacheSet(face,
5840 glyph_index,
5841 plf->lfHeight,
5842 pmxWorldToDevice,
5843 glyph,
5844 RenderMode);
5845 }
5846 if (!realglyph)
5847 {
5848 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5849 bResult = FALSE;
5850 break;
5851 }
5852 }
5853
5854 /* retrieve kerning distance and move pen position */
5855 if (use_kerning && previous && glyph_index && NULL == Dx)
5856 {
5857 FT_Vector delta;
5858 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5859 TextLeft += delta.x;
5860 }
5861 DPRINT("TextLeft: %I64d\n", TextLeft);
5862 DPRINT("TextTop: %lu\n", TextTop);
5863 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5864
5865 if ((fuOptions & ETO_OPAQUE) && !plf->lfItalic)
5866 {
5867 DestRect.left = BackgroundLeft;
5868 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5869 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5870 DestRect.bottom = DestRect.top + ((fixAscender + fixDescender) >> 6);
5871
5872 if (dc->dctype == DCTYPE_DIRECT)
5873 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5874
5875 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5876 {
5877 IntUpdateBoundsRect(dc, &DestRect);
5878 }
5879 IntEngBitBlt(
5880 &psurf->SurfObj,
5881 NULL,
5882 NULL,
5883 (CLIPOBJ *)&dc->co,
5884 NULL,
5885 &DestRect,
5886 &SourcePoint,
5887 &SourcePoint,
5888 &dc->eboBackground.BrushObject,
5889 &BrushOrigin,
5890 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5891
5892 if (dc->dctype == DCTYPE_DIRECT)
5893 MouseSafetyOnDrawEnd(dc->ppdev);
5894
5895 BackgroundLeft = DestRect.right;
5896 }
5897
5898 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5899 DestRect.right = DestRect.left + realglyph->bitmap.width;
5900 DestRect.top = TextTop + yoff - realglyph->top;
5901 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5902
5903 bitSize.cx = realglyph->bitmap.width;
5904 bitSize.cy = realglyph->bitmap.rows;
5905 MaskRect.right = realglyph->bitmap.width;
5906 MaskRect.bottom = realglyph->bitmap.rows;
5907
5908 /* Check if the bitmap has any pixels */
5909 if ((bitSize.cx != 0) && (bitSize.cy != 0))
5910 {
5911 /*
5912 * We should create the bitmap out of the loop at the biggest possible
5913 * glyph size. Then use memset with 0 to clear it and sourcerect to
5914 * limit the work of the transbitblt.
5915 */
5916 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
5917 BMF_8BPP, BMF_TOPDOWN,
5918 realglyph->bitmap.buffer);
5919 if ( !HSourceGlyph )
5920 {
5921 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
5922 // FT_Done_Glyph(realglyph);
5923 bResult = FALSE;
5924 break;
5925 }
5926 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
5927 if ( !SourceGlyphSurf )
5928 {
5929 EngDeleteSurface((HSURF)HSourceGlyph);
5930 DPRINT1("WARNING: EngLockSurface() failed!\n");
5931 bResult = FALSE;
5932 break;
5933 }
5934
5935 /*
5936 * Use the font data as a mask to paint onto the DCs surface using a
5937 * brush.
5938 */
5939 if (lprc && (fuOptions & ETO_CLIPPED) &&
5940 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
5941 {
5942 // We do the check '>=' instead of '>' to possibly save an iteration
5943 // through this loop, since it's breaking after the drawing is done,
5944 // and x is always incremented.
5945 DestRect.right = lprc->right + dc->ptlDCOrig.x;
5946 DoBreak = TRUE;
5947 }
5948 if (lprc && (fuOptions & ETO_CLIPPED) &&
5949 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
5950 {
5951 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
5952 }
5953
5954 if (dc->dctype == DCTYPE_DIRECT)
5955 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5956
5957 if (!IntEngMaskBlt(
5958 SurfObj,
5959 SourceGlyphSurf,
5960 (CLIPOBJ *)&dc->co,
5961 &exloRGB2Dst.xlo,
5962 &exloDst2RGB.xlo,
5963 &DestRect,
5964 (PPOINTL)&MaskRect,
5965 &dc->eboText.BrushObject,
5966 &BrushOrigin))
5967 {
5968 DPRINT1("Failed to MaskBlt a glyph!\n");
5969 }
5970
5971 if (dc->dctype == DCTYPE_DIRECT)
5972 MouseSafetyOnDrawEnd(dc->ppdev) ;
5973
5974 EngUnlockSurface(SourceGlyphSurf);
5975 EngDeleteSurface((HSURF)HSourceGlyph);
5976 }
5977
5978 if (DoBreak)
5979 {
5980 break;
5981 }
5982
5983 if (plf->lfUnderline)
5984 {
5985 int i, position;
5986 if (!face->units_per_EM)
5987 {
5988 position = 0;
5989 }
5990 else
5991 {
5992 position = face->underline_position *
5993 face->size->metrics.y_ppem / face->units_per_EM;
5994 }
5995 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5996 {
5997 EngLineTo(SurfObj,
5998 (CLIPOBJ *)&dc->co,
5999 &dc->eboText.BrushObject,
6000 (TextLeft >> 6),
6001 TextTop + yoff - position + i,
6002 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
6003 TextTop + yoff - position + i,
6004 NULL,
6005 ROP2_TO_MIX(R2_COPYPEN));
6006 }
6007 }
6008 if (plf->lfStrikeOut)
6009 {
6010 int i;
6011 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
6012 {
6013 EngLineTo(SurfObj,
6014 (CLIPOBJ *)&dc->co,
6015 &dc->eboText.BrushObject,
6016 (TextLeft >> 6),
6017 TextTop + yoff - (fixAscender >> 6) / 3 + i,
6018 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
6019 TextTop + yoff - (fixAscender >> 6) / 3 + i,
6020 NULL,
6021 ROP2_TO_MIX(R2_COPYPEN));
6022 }
6023 }
6024
6025 if (NULL == Dx)
6026 {
6027 TextLeft += realglyph->root.advance.x >> 10;
6028 DPRINT("New TextLeft: %I64d\n", TextLeft);
6029 }
6030 else
6031 {
6032 // FIXME this should probably be a matrix transform with TextTop as well.
6033 Scale = pdcattr->mxWorldToDevice.efM11;
6034 if (FLOATOBJ_Equal0(&Scale))
6035 FLOATOBJ_Set1(&Scale);
6036
6037 /* do the shift before multiplying to preserve precision */
6038 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
6039 TextLeft += FLOATOBJ_GetLong(&Scale);
6040 DPRINT("New TextLeft2: %I64d\n", TextLeft);
6041 }
6042
6043 if (DxShift)
6044 {
6045 TextTop -= Dx[2 * i + 1] << 6;
6046 }
6047
6048 previous = glyph_index;
6049
6050 if (EmuBold || EmuItalic)
6051 {
6052 FT_Done_Glyph((FT_Glyph)realglyph);
6053 realglyph = NULL;
6054 }
6055 }
6056
6057 if (pdcattr->lTextAlign & TA_UPDATECP) {
6058 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
6059 }
6060
6061 IntUnLockFreeType();
6062
6063 EXLATEOBJ_vCleanup(&exloRGB2Dst);
6064 EXLATEOBJ_vCleanup(&exloDst2RGB);
6065
6066 Cleanup:
6067
6068 DC_vFinishBlit(dc, NULL);
6069
6070 if (TextObj != NULL)
6071 TEXTOBJ_UnlockText(TextObj);
6072
6073 DC_UnlockDc(dc);
6074
6075 return bResult;
6076 }
6077
6078 #define STACK_TEXT_BUFFER_SIZE 100
6079 BOOL
6080 APIENTRY
6081 NtGdiExtTextOutW(
6082 IN HDC hDC,
6083 IN INT XStart,
6084 IN INT YStart,
6085 IN UINT fuOptions,
6086 IN OPTIONAL LPRECT UnsafeRect,
6087 IN LPWSTR UnsafeString,
6088 IN INT Count,
6089 IN OPTIONAL LPINT UnsafeDx,
6090 IN DWORD dwCodePage)
6091 {
6092 BOOL Result = FALSE;
6093 NTSTATUS Status = STATUS_SUCCESS;
6094 RECTL SafeRect;
6095 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
6096 PVOID Buffer = LocalBuffer;
6097 LPCWSTR SafeString = NULL;
6098 LPINT SafeDx = NULL;
6099 ULONG BufSize, StringSize, DxSize = 0;
6100
6101 /* Check if String is valid */
6102 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
6103 {
6104 EngSetLastError(ERROR_INVALID_PARAMETER);
6105 return FALSE;
6106 }
6107
6108 if (Count > 0)
6109 {
6110 /* Calculate buffer size for string and Dx values */
6111 BufSize = StringSize = Count * sizeof(WCHAR);
6112 if (UnsafeDx)
6113 {
6114 /* If ETO_PDY is specified, we have pairs of INTs */
6115 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
6116 BufSize += DxSize;
6117 }
6118
6119 /* Check if our local buffer is large enough */
6120 if (BufSize > STACK_TEXT_BUFFER_SIZE)
6121 {
6122 /* It's not, allocate a temp buffer */
6123 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
6124 if (!Buffer)
6125 {
6126 return FALSE;
6127 }
6128 }
6129
6130 /* Probe and copy user mode data to the buffer */
6131 _SEH2_TRY
6132 {
6133 /* Put the Dx before the String to assure alignment of 4 */
6134 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
6135
6136 /* Probe and copy the string */
6137 ProbeForRead(UnsafeString, StringSize, 1);
6138 memcpy((PVOID)SafeString, UnsafeString, StringSize);
6139
6140 /* If we have Dx values... */
6141 if (UnsafeDx)
6142 {
6143 /* ... probe and copy them */
6144 SafeDx = Buffer;
6145 ProbeForRead(UnsafeDx, DxSize, 1);
6146 memcpy(SafeDx, UnsafeDx, DxSize);
6147 }
6148 }
6149 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6150 {
6151 Status = _SEH2_GetExceptionCode();
6152 }
6153 _SEH2_END
6154 if (!NT_SUCCESS(Status))
6155 {
6156 goto cleanup;
6157 }
6158 }
6159
6160 /* If we have a rect, copy it */
6161 if (UnsafeRect)
6162 {
6163 _SEH2_TRY
6164 {
6165 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
6166 SafeRect = *UnsafeRect;
6167 }
6168 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6169 {
6170 Status = _SEH2_GetExceptionCode();
6171 }
6172 _SEH2_END
6173 if (!NT_SUCCESS(Status))
6174 {
6175 goto cleanup;
6176 }
6177 }
6178
6179 /* Finally call the internal routine */
6180 Result = GreExtTextOutW(hDC,
6181 XStart,
6182 YStart,
6183 fuOptions,
6184 &SafeRect,
6185 SafeString,
6186 Count,
6187 SafeDx,
6188 dwCodePage);
6189
6190 cleanup:
6191 /* If we allocated a buffer, free it */
6192 if (Buffer != LocalBuffer)
6193 {
6194 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6195 }
6196
6197 return Result;
6198 }
6199
6200
6201 /*
6202 * @implemented
6203 */
6204 BOOL
6205 APIENTRY
6206 NtGdiGetCharABCWidthsW(
6207 IN HDC hDC,
6208 IN UINT FirstChar,
6209 IN ULONG Count,
6210 IN OPTIONAL PWCHAR UnSafepwch,
6211 IN FLONG fl,
6212 OUT PVOID Buffer)
6213 {
6214 LPABC SafeBuff;
6215 LPABCFLOAT SafeBuffF = NULL;
6216 PDC dc;
6217 PDC_ATTR pdcattr;
6218 PTEXTOBJ TextObj;
6219 PFONTGDI FontGDI;
6220 FT_Face face;
6221 FT_CharMap charmap, found = NULL;
6222 UINT i, glyph_index, BufferSize;
6223 HFONT hFont = 0;
6224 NTSTATUS Status = STATUS_SUCCESS;
6225 PMATRIX pmxWorldToDevice;
6226 PWCHAR Safepwch = NULL;
6227 LOGFONTW *plf;
6228
6229 if (!Buffer)
6230 {
6231 EngSetLastError(ERROR_INVALID_PARAMETER);
6232 return FALSE;
6233 }
6234
6235 if (UnSafepwch)
6236 {
6237 UINT pwchSize = Count * sizeof(WCHAR);
6238 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
6239
6240 if(!Safepwch)
6241 {
6242 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6243 return FALSE;
6244 }
6245
6246 _SEH2_TRY
6247 {
6248 ProbeForRead(UnSafepwch, pwchSize, 1);
6249 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
6250 }
6251 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6252 {
6253 Status = _SEH2_GetExceptionCode();
6254 }
6255 _SEH2_END;
6256 }
6257
6258 if (!NT_SUCCESS(Status))
6259 {
6260 if(Safepwch)
6261 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6262
6263 EngSetLastError(Status);
6264 return FALSE;
6265 }
6266
6267 BufferSize = Count * sizeof(ABC); // Same size!
6268 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6269 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
6270 if (SafeBuff == NULL)
6271 {
6272
6273 if(Safepwch)
6274 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6275
6276 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6277 return FALSE;
6278 }
6279
6280 dc = DC_LockDc(hDC);
6281 if (dc == NULL)
6282 {
6283 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6284
6285 if(Safepwch)
6286 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6287
6288 EngSetLastError(ERROR_INVALID_HANDLE);
6289 return FALSE;
6290 }
6291 pdcattr = dc->pdcattr;
6292 hFont = pdcattr->hlfntNew;
6293 TextObj = RealizeFontInit(hFont);
6294
6295 /* Get the DC's world-to-device transformation matrix */
6296 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6297 DC_UnlockDc(dc);
6298
6299 if (TextObj == NULL)
6300 {
6301 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6302
6303 if(Safepwch)
6304 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6305
6306 EngSetLastError(ERROR_INVALID_HANDLE);
6307 return FALSE;
6308 }
6309
6310 FontGDI = ObjToGDI(TextObj->Font, FONT);
6311
6312 face = FontGDI->SharedFace->Face;
6313 if (face->charmap == NULL)
6314 {
6315 for (i = 0; i < (UINT)face->num_charmaps; i++)
6316 {
6317 charmap = face->charmaps[i];
6318 if (charmap->encoding != 0)
6319 {
6320 found = charmap;
6321 break;
6322 }
6323 }
6324
6325 if (!found)
6326 {
6327 DPRINT1("WARNING: Could not find desired charmap!\n");
6328 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6329
6330 if(Safepwch)
6331 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6332
6333 EngSetLastError(ERROR_INVALID_HANDLE);
6334 return FALSE;
6335 }
6336
6337 IntLockFreeType();
6338 FT_Set_Charmap(face, found);
6339 IntUnLockFreeType();
6340 }
6341
6342 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6343 IntLockFreeType();
6344 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
6345 FtSetCoordinateTransform(face, pmxWorldToDevice);
6346
6347 for (i = FirstChar; i < FirstChar+Count; i++)
6348 {
6349 int adv, lsb, bbx, left, right;
6350
6351 if (Safepwch)
6352 {
6353 glyph_index = get_glyph_index_flagged(face, Safepwch[i - FirstChar], GCABCW_INDICES, fl);
6354 }
6355 else
6356 {
6357 glyph_index = get_glyph_index_flagged(face, i, GCABCW_INDICES, fl);
6358 }
6359 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6360
6361 left = (INT)face->glyph->metrics.horiBearingX & -64;
6362 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
6363 adv = (face->glyph->advance.x + 32) >> 6;
6364
6365 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
6366 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
6367
6368 lsb = left >> 6;
6369 bbx = (right - left) >> 6;
6370 /*
6371 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
6372 */
6373 if (!fl)
6374 {
6375 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
6376 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
6377 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
6378 }
6379 else
6380 {
6381 SafeBuff[i - FirstChar].abcA = lsb;
6382 SafeBuff[i - FirstChar].abcB = bbx;
6383 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
6384 }
6385 }
6386 IntUnLockFreeType();
6387 TEXTOBJ_UnlockText(TextObj);
6388 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6389
6390 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6391
6392 if(Safepwch)
6393 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6394
6395 if (! NT_SUCCESS(Status))
6396 {
6397 SetLastNtError(Status);
6398 return FALSE;
6399 }
6400
6401 DPRINT("NtGdiGetCharABCWidths Worked!\n");
6402 return TRUE;
6403 }
6404
6405 /*
6406 * @implemented
6407 */
6408 BOOL
6409 APIENTRY
6410 NtGdiGetCharWidthW(
6411 IN HDC hDC,
6412 IN UINT FirstChar,
6413 IN UINT Count,
6414 IN OPTIONAL PWCHAR UnSafepwc,
6415 IN FLONG fl,
6416 OUT PVOID Buffer)
6417 {
6418 NTSTATUS Status = STATUS_SUCCESS;
6419 LPINT SafeBuff;
6420 PFLOAT SafeBuffF = NULL;
6421 PDC dc;
6422 PDC_ATTR pdcattr;
6423 PTEXTOBJ TextObj;
6424 PFONTGDI FontGDI;
6425 FT_Face face;
6426 FT_CharMap charmap, found = NULL;
6427 UINT i, glyph_index, BufferSize;
6428 HFONT hFont = 0;
6429 PMATRIX pmxWorldToDevice;
6430 PWCHAR Safepwc = NULL;
6431 LOGFONTW *plf;
6432
6433 if (UnSafepwc)
6434 {
6435 UINT pwcSize = Count * sizeof(WCHAR);
6436 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6437
6438 if(!Safepwc)
6439 {
6440 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6441 return FALSE;
6442 }
6443 _SEH2_TRY
6444 {
6445 ProbeForRead(UnSafepwc, pwcSize, 1);
6446 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6447 }
6448 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6449 {
6450 Status = _SEH2_GetExceptionCode();
6451 }
6452 _SEH2_END;
6453 }
6454
6455 if (!NT_SUCCESS(Status))
6456 {
6457 EngSetLastError(Status);
6458 return FALSE;
6459 }
6460
6461 BufferSize = Count * sizeof(INT); // Same size!
6462 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6463 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
6464 if (SafeBuff == NULL)
6465 {
6466 if(Safepwc)
6467 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6468
6469 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6470 return FALSE;
6471 }
6472
6473 dc = DC_LockDc(hDC);
6474 if (dc == NULL)
6475 {
6476 if(Safepwc)
6477 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6478
6479 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6480 EngSetLastError(ERROR_INVALID_HANDLE);
6481 return FALSE;
6482 }
6483 pdcattr = dc->pdcattr;
6484 hFont = pdcattr->hlfntNew;
6485 TextObj = RealizeFontInit(hFont);
6486 /* Get the DC's world-to-device transformation matrix */
6487 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6488 DC_UnlockDc(dc);
6489
6490 if (TextObj == NULL)
6491 {
6492 if(Safepwc)
6493 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6494
6495 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6496 EngSetLastError(ERROR_INVALID_HANDLE);
6497 return FALSE;
6498 }
6499
6500 FontGDI = ObjToGDI(TextObj->Font, FONT);
6501
6502 face = FontGDI->SharedFace->Face;
6503 if (face->charmap == NULL)
6504 {
6505 for (i = 0; i < (UINT)face->num_charmaps; i++)
6506 {
6507 charmap = face->charmaps[i];
6508 if (charmap->encoding != 0)
6509 {
6510 found = charmap;
6511 break;
6512 }
6513 }
6514
6515 if (!found)
6516 {
6517 DPRINT1("WARNING: Could not find desired charmap!\n");
6518
6519 if(Safepwc)
6520 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6521
6522 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6523 EngSetLastError(ERROR_INVALID_HANDLE);
6524 return FALSE;
6525 }
6526
6527 IntLockFreeType();
6528 FT_Set_Charmap(face, found);
6529 IntUnLockFreeType();
6530 }
6531
6532 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6533 IntLockFreeType();
6534 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
6535 FtSetCoordinateTransform(face, pmxWorldToDevice);
6536
6537 for (i = FirstChar; i < FirstChar+Count; i++)
6538 {
6539 if (Safepwc)
6540 {
6541 glyph_index = get_glyph_index_flagged(face, Safepwc[i - FirstChar], GCW_INDICES, fl);
6542 }
6543 else
6544 {
6545 glyph_index = get_glyph_index_flagged(face, i, GCW_INDICES, fl);
6546 }
6547 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6548 if (!fl)
6549 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
6550 else
6551 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
6552 }
6553 IntUnLockFreeType();
6554 TEXTOBJ_UnlockText(TextObj);
6555 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6556
6557 if(Safepwc)
6558 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6559
6560 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6561 return TRUE;
6562 }
6563
6564
6565 /*
6566 * @implemented
6567 */
6568 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
6569 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
6570 // NOTE: See also GreGetGlyphIndicesW.
6571 __kernel_entry
6572 W32KAPI
6573 DWORD
6574 APIENTRY
6575 NtGdiGetGlyphIndicesW(
6576 _In_ HDC hdc,
6577 _In_reads_opt_(cwc) LPCWSTR pwc,
6578 _In_ INT cwc,
6579 _Out_writes_opt_(cwc) LPWORD pgi,
6580 _In_ DWORD iMode)
6581 {
6582 PDC dc;
6583 PDC_ATTR pdcattr;
6584 PTEXTOBJ TextObj;
6585 PFONTGDI FontGDI;
6586 HFONT hFont = NULL;
6587 NTSTATUS Status = STATUS_SUCCESS;
6588 OUTLINETEXTMETRICW *potm;
6589 INT i;
6590 WCHAR DefChar = 0xffff;
6591 PWSTR Buffer = NULL;
6592 ULONG Size, pwcSize;
6593 PWSTR Safepwc = NULL;
6594 LPCWSTR UnSafepwc = pwc;
6595 LPWORD UnSafepgi = pgi;
6596
6597 /* Check for integer overflow */
6598 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN
6599 return GDI_ERROR;
6600
6601 if (!UnSafepwc && !UnSafepgi)
6602 return cwc;
6603
6604 if (!UnSafepwc || !UnSafepgi)
6605 {
6606 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
6607 return GDI_ERROR;
6608 }
6609
6610 // TODO: Special undocumented case!
6611 if (!pwc && !pgi && (cwc == 0))
6612 {
6613 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n");
6614 return 0;
6615 }
6616
6617 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825
6618 if (cwc == 0)
6619 {
6620 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n");
6621 return GDI_ERROR;
6622 }
6623
6624 dc = DC_LockDc(hdc);
6625 if (!dc)
6626 {
6627 return GDI_ERROR;
6628 }
6629 pdcattr = dc->pdcattr;
6630 hFont = pdcattr->hlfntNew;
6631 TextObj = RealizeFontInit(hFont);
6632 DC_UnlockDc(dc);
6633 if (!TextObj)
6634 {
6635 return GDI_ERROR;
6636 }
6637
6638 FontGDI = ObjToGDI(TextObj->Font, FONT);
6639 TEXTOBJ_UnlockText(TextObj);
6640
6641 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
6642 if (!Buffer)
6643 {
6644 return GDI_ERROR;
6645 }
6646
6647 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
6648 {
6649 DefChar = 0xffff;
6650 }
6651 else
6652 {
6653 FT_Face Face = FontGDI->SharedFace->Face;
6654 if (FT_IS_SFNT(Face))
6655 {
6656 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
6657 DefChar = (pOS2->usDefaultChar ? get_glyph_index(Face, pOS2->usDefaultChar) : 0);
6658 }
6659 else
6660 {
6661 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
6662 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
6663 if (!potm)
6664 {
6665 cwc = GDI_ERROR;
6666 goto ErrorRet;
6667 }
6668 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
6669 if (Size)
6670 DefChar = potm->otmTextMetrics.tmDefaultChar;
6671 ExFreePoolWithTag(potm, GDITAG_TEXT);
6672 }
6673 }
6674
6675 pwcSize = cwc * sizeof(WCHAR);
6676 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6677
6678 if (!Safepwc)
6679 {
6680 Status = STATUS_NO_MEMORY;
6681 goto ErrorRet;
6682 }
6683
6684 _SEH2_TRY
6685 {
6686 ProbeForRead(UnSafepwc, pwcSize, 1);
6687 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6688 }
6689 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6690 {
6691 Status = _SEH2_GetExceptionCode();
6692 }
6693 _SEH2_END;
6694
6695 if (!NT_SUCCESS(Status)) goto ErrorRet;
6696
6697 IntLockFreeType();
6698
6699 for (i = 0; i < cwc; i++)
6700 {
6701 Buffer[i] = get_glyph_index(FontGDI->SharedFace->Face, Safepwc[i]);
6702 if (Buffer[i] == 0)
6703 {
6704 Buffer[i] = DefChar;
6705 }
6706 }
6707
6708 IntUnLockFreeType();
6709
6710 _SEH2_TRY
6711 {
6712 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
6713 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
6714 }
6715 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6716 {
6717 Status = _SEH2_GetExceptionCode();
6718 }
6719 _SEH2_END;
6720
6721 ErrorRet:
6722 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6723 if (Safepwc != NULL)
6724 {
6725 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6726 }
6727 if (NT_SUCCESS(Status)) return cwc;
6728 return GDI_ERROR;
6729 }
6730
6731 /* EOF */