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