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