c201b3d69844c3d89cb09687a61eddbfbb53e93a
[reactos.git] / win32ss / gdi / ntgdi / freetype.c
1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/freetype.c
5 * PURPOSE: FreeType font engine interface
6 * PROGRAMMERS: Copyright 2001 Huw D M Davies for CodeWeavers.
7 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
8 * Copyright 2016-2018 Katayama Hirofumi MZ.
9 */
10
11 /** Includes ******************************************************************/
12
13 #include <win32k.h>
14
15 #include FT_GLYPH_H
16 #include FT_TYPE1_TABLES_H
17 #include FT_TRUETYPE_TABLES_H
18 #include FT_TRUETYPE_TAGS_H
19 #include FT_TRIGONOMETRY_H
20 #include FT_BITMAP_H
21 #include FT_OUTLINE_H
22 #include FT_WINFONTS_H
23 #include FT_SFNT_NAMES_H
24 #include FT_SYNTHESIS_H
25 #include FT_TRUETYPE_IDS_H
26
27 #ifndef FT_INTERNAL_INTERNAL_H
28 #define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h>
29 #include FT_INTERNAL_INTERNAL_H
30 #endif
31 #include FT_INTERNAL_TRUETYPE_TYPES_H
32
33 #include <gdi/eng/floatobj.h>
34 #include "font.h"
35
36 #define NDEBUG
37 #include <debug.h>
38
39 /* TPMF_FIXED_PITCH is confusing; brain-dead api */
40 #ifndef _TMPF_VARIABLE_PITCH
41 #define _TMPF_VARIABLE_PITCH TMPF_FIXED_PITCH
42 #endif
43
44 extern const MATRIX gmxWorldToDeviceDefault;
45 extern const MATRIX gmxWorldToPageDefault;
46
47 /* HACK!! Fix XFORMOBJ then use 1:16 / 16:1 */
48 #define gmxWorldToDeviceDefault gmxWorldToPageDefault
49
50 FT_Library g_FreeTypeLibrary;
51
52 /* special font names */
53 static const UNICODE_STRING g_MarlettW = RTL_CONSTANT_STRING(L"Marlett");
54
55 /* registry */
56 static UNICODE_STRING g_FontRegPath =
57 RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
58
59
60 /* The FreeType library is not thread safe, so we have
61 to serialize access to it */
62 static PFAST_MUTEX g_FreeTypeLock;
63
64 static LIST_ENTRY g_FontListHead;
65 static PFAST_MUTEX g_FontListLock;
66 static BOOL g_RenderingEnabled = TRUE;
67
68 #define IntLockGlobalFonts() \
69 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FontListLock)
70
71 #define IntUnLockGlobalFonts() \
72 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FontListLock)
73
74 #define ASSERT_GLOBALFONTS_LOCK_HELD() \
75 ASSERT(g_FontListLock->Owner == KeGetCurrentThread())
76
77 #define IntLockFreeType() \
78 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FreeTypeLock)
79
80 #define IntUnLockFreeType() \
81 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FreeTypeLock)
82
83 #define ASSERT_FREETYPE_LOCK_HELD() \
84 ASSERT(g_FreeTypeLock->Owner == KeGetCurrentThread())
85
86 #define ASSERT_FREETYPE_LOCK_NOT_HELD() \
87 ASSERT(g_FreeTypeLock->Owner != KeGetCurrentThread())
88
89 #define MAX_FONT_CACHE 256
90
91 static LIST_ENTRY g_FontCacheListHead;
92 static UINT g_FontCacheNumEntries;
93
94 static PWCHAR g_ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */
95 {
96 L"Western", /* 00 */
97 L"Central_European",
98 L"Cyrillic",
99 L"Greek",
100 L"Turkish",
101 L"Hebrew",
102 L"Arabic",
103 L"Baltic",
104 L"Vietnamese", /* 08 */
105 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */
106 L"Thai",
107 L"Japanese",
108 L"CHINESE_GB2312",
109 L"Hangul",
110 L"CHINESE_BIG5",
111 L"Hangul(Johab)",
112 NULL, NULL, /* 23 */
113 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
114 L"Symbol" /* 31 */
115 };
116
117 /*
118 * For TranslateCharsetInfo
119 */
120 #define CP_SYMBOL 42
121 #define MAXTCIINDEX 32
122 static const CHARSETINFO g_FontTci[MAXTCIINDEX] =
123 {
124 /* ANSI */
125 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
126 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
127 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
128 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
129 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
130 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
131 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
132 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
133 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
134 /* reserved by ANSI */
135 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
136 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
137 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
138 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
139 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
140 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
141 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
142 /* ANSI and OEM */
143 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
144 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
145 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
146 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
147 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
148 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
149 /* Reserved for alternate ANSI and OEM */
150 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
151 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
152 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
153 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
154 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
155 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
157 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
158 /* Reserved for system */
159 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
160 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
161 };
162
163 /* 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, PFONTGDI FontGDI, LONG Width, LONG Height)
2999 {
3000 FT_Size_RequestRec req;
3001 FT_Face face = FontGDI->SharedFace->Face;
3002
3003 if (Width < 0)
3004 Width = -Width;
3005
3006 if (Height < 0)
3007 {
3008 Height = -Height;
3009 }
3010 if (Height == 0)
3011 {
3012 Height = dc->ppdev->devinfo.lfDefaultFont.lfHeight;
3013 }
3014 if (Height == 0)
3015 {
3016 Height = Width;
3017 }
3018
3019 if (Height < 1)
3020 Height = 1;
3021
3022 if (Width > 0xFFFFU)
3023 Width = 0xFFFFU;
3024 if (Height > 0xFFFFU)
3025 Height = 0xFFFFU;
3026
3027 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
3028 req.width = (FT_Long)(Width << 6);
3029 req.height = (FT_Long)(Height << 6);
3030 req.horiResolution = 0;
3031 req.vertResolution = 0;
3032 return FT_Request_Size(face, &req);
3033 }
3034
3035 BOOL
3036 FASTCALL
3037 TextIntUpdateSize(PDC dc,
3038 PTEXTOBJ TextObj,
3039 PFONTGDI FontGDI,
3040 BOOL bDoLock)
3041 {
3042 FT_Face face;
3043 INT error, n;
3044 FT_CharMap charmap, found;
3045 LOGFONTW *plf;
3046
3047 if (bDoLock)
3048 IntLockFreeType();
3049
3050 face = FontGDI->SharedFace->Face;
3051 if (face->charmap == NULL)
3052 {
3053 DPRINT("WARNING: No charmap selected!\n");
3054 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3055
3056 found = NULL;
3057 for (n = 0; n < face->num_charmaps; n++)
3058 {
3059 charmap = face->charmaps[n];
3060 DPRINT("Found charmap encoding: %i\n", charmap->encoding);
3061 if (charmap->encoding != 0)
3062 {
3063 found = charmap;
3064 break;
3065 }
3066 }
3067 if (!found)
3068 {
3069 DPRINT1("WARNING: Could not find desired charmap!\n");
3070 }
3071 else
3072 {
3073 error = FT_Set_Charmap(face, found);
3074 if (error)
3075 {
3076 DPRINT1("WARNING: Could not set the charmap!\n");
3077 }
3078 }
3079 }
3080
3081 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3082
3083 error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
3084
3085 if (bDoLock)
3086 IntUnLockFreeType();
3087
3088 if (error)
3089 {
3090 DPRINT1("Error in setting pixel sizes: %d\n", error);
3091 return FALSE;
3092 }
3093
3094 return TRUE;
3095 }
3096
3097
3098 /*
3099 * Based on WineEngGetGlyphOutline
3100 *
3101 */
3102 ULONG
3103 FASTCALL
3104 ftGdiGetGlyphOutline(
3105 PDC dc,
3106 WCHAR wch,
3107 UINT iFormat,
3108 LPGLYPHMETRICS pgm,
3109 ULONG cjBuf,
3110 PVOID pvBuf,
3111 LPMAT2 pmat2,
3112 BOOL bIgnoreRotation)
3113 {
3114 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3115 PDC_ATTR pdcattr;
3116 PTEXTOBJ TextObj;
3117 PFONTGDI FontGDI;
3118 HFONT hFont = 0;
3119 GLYPHMETRICS gm;
3120 ULONG Size;
3121 FT_Face ft_face;
3122 FT_UInt glyph_index;
3123 DWORD width, height, pitch, needed = 0;
3124 FT_Bitmap ft_bitmap;
3125 FT_Error error;
3126 INT left, right, top = 0, bottom = 0;
3127 FT_Angle angle = 0;
3128 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3129 FLOAT eM11, widthRatio = 1.0;
3130 FT_Matrix transMat = identityMat;
3131 BOOL needsTransform = FALSE;
3132 INT orientation;
3133 LONG aveWidth;
3134 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3135 OUTLINETEXTMETRICW *potm;
3136 XFORM xForm;
3137 LOGFONTW *plf;
3138
3139 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3140 cjBuf, pvBuf, pmat2);
3141
3142 pdcattr = dc->pdcattr;
3143
3144 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
3145 eM11 = xForm.eM11;
3146
3147 hFont = pdcattr->hlfntNew;
3148 TextObj = RealizeFontInit(hFont);
3149
3150 if (!TextObj)
3151 {
3152 EngSetLastError(ERROR_INVALID_HANDLE);
3153 return GDI_ERROR;
3154 }
3155 FontGDI = ObjToGDI(TextObj->Font, FONT);
3156 ft_face = FontGDI->SharedFace->Face;
3157
3158 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3159 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3160 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3161
3162 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3163 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3164 if (!potm)
3165 {
3166 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3167 TEXTOBJ_UnlockText(TextObj);
3168 return GDI_ERROR;
3169 }
3170 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
3171 if (!Size)
3172 {
3173 /* FIXME: last error? */
3174 ExFreePoolWithTag(potm, GDITAG_TEXT);
3175 TEXTOBJ_UnlockText(TextObj);
3176 return GDI_ERROR;
3177 }
3178
3179 IntLockFreeType();
3180 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3181 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
3182
3183 TEXTOBJ_UnlockText(TextObj);
3184
3185 if (iFormat & GGO_GLYPH_INDEX)
3186 {
3187 glyph_index = wch;
3188 iFormat &= ~GGO_GLYPH_INDEX;
3189 }
3190 else glyph_index = FT_Get_Char_Index(ft_face, wch);
3191
3192 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3193 load_flags |= FT_LOAD_NO_BITMAP;
3194
3195 if (iFormat & GGO_UNHINTED)
3196 {
3197 load_flags |= FT_LOAD_NO_HINTING;
3198 iFormat &= ~GGO_UNHINTED;
3199 }
3200
3201 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3202 if (error)
3203 {
3204 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3205 IntUnLockFreeType();
3206 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3207 return GDI_ERROR;
3208 }
3209 IntUnLockFreeType();
3210
3211 if (aveWidth && potm)
3212 {
3213 widthRatio = (FLOAT)aveWidth * eM11 /
3214 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
3215 }
3216
3217 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3218 right = (INT)((ft_face->glyph->metrics.horiBearingX +
3219 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3220
3221 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3222 lsb = left >> 6;
3223 bbx = (right - left) >> 6;
3224
3225 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3226
3227 IntLockFreeType();
3228
3229 /* Scaling transform */
3230 /*if (aveWidth)*/
3231 {
3232
3233 FT_Matrix ftmatrix;
3234 FLOATOBJ efTemp;
3235
3236 PMATRIX pmx = DC_pmxWorldToDevice(dc);
3237
3238 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3239 efTemp = pmx->efM11;
3240 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3241 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
3242
3243 efTemp = pmx->efM12;
3244 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3245 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
3246
3247 efTemp = pmx->efM21;
3248 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3249 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
3250
3251 efTemp = pmx->efM22;
3252 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3253 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
3254
3255 FT_Matrix_Multiply(&ftmatrix, &transMat);
3256 needsTransform = TRUE;
3257 }
3258
3259 /* Rotation transform */
3260 if (orientation)
3261 {
3262 FT_Matrix rotationMat;
3263 FT_Vector vecAngle;
3264 DPRINT("Rotation Trans!\n");
3265 angle = FT_FixedFromFloat((float)orientation / 10.0);
3266 FT_Vector_Unit(&vecAngle, angle);
3267 rotationMat.xx = vecAngle.x;
3268 rotationMat.xy = -vecAngle.y;
3269 rotationMat.yx = -rotationMat.xy;
3270 rotationMat.yy = rotationMat.xx;
3271 FT_Matrix_Multiply(&rotationMat, &transMat);
3272 needsTransform = TRUE;
3273 }
3274
3275 /* Extra transformation specified by caller */
3276 if (pmat2)
3277 {
3278 FT_Matrix extraMat;
3279 DPRINT("MAT2 Matrix Trans!\n");
3280 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
3281 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
3282 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
3283 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
3284 FT_Matrix_Multiply(&extraMat, &transMat);
3285 needsTransform = TRUE;
3286 }
3287
3288 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
3289
3290 if (!needsTransform)
3291 {
3292 DPRINT("No Need to be Transformed!\n");
3293 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3294 bottom = (ft_face->glyph->metrics.horiBearingY -
3295 ft_face->glyph->metrics.height) & -64;
3296 gm.gmCellIncX = adv;
3297 gm.gmCellIncY = 0;
3298 }
3299 else
3300 {
3301 INT xc, yc;
3302 FT_Vector vec;
3303 for (xc = 0; xc < 2; xc++)
3304 {
3305 for (yc = 0; yc < 2; yc++)
3306 {
3307 vec.x = (ft_face->glyph->metrics.horiBearingX +
3308 xc * ft_face->glyph->metrics.width);
3309 vec.y = ft_face->glyph->metrics.horiBearingY -
3310 yc * ft_face->glyph->metrics.height;
3311 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
3312 FT_Vector_Transform(&vec, &transMat);
3313 if (xc == 0 && yc == 0)
3314 {
3315 left = right = vec.x;
3316 top = bottom = vec.y;
3317 }
3318 else
3319 {
3320 if (vec.x < left) left = vec.x;
3321 else if (vec.x > right) right = vec.x;
3322 if (vec.y < bottom) bottom = vec.y;
3323 else if (vec.y > top) top = vec.y;
3324 }
3325 }
3326 }
3327 left = left & -64;
3328 right = (right + 63) & -64;
3329 bottom = bottom & -64;
3330 top = (top + 63) & -64;
3331
3332 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3333 vec.x = ft_face->glyph->metrics.horiAdvance;
3334 vec.y = 0;
3335 FT_Vector_Transform(&vec, &transMat);
3336 gm.gmCellIncX = (vec.x+63) >> 6;
3337 gm.gmCellIncY = -((vec.y+63) >> 6);
3338 }
3339 gm.gmBlackBoxX = (right - left) >> 6;
3340 gm.gmBlackBoxY = (top - bottom) >> 6;
3341 gm.gmptGlyphOrigin.x = left >> 6;
3342 gm.gmptGlyphOrigin.y = top >> 6;
3343
3344 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
3345 gm.gmCellIncX, gm.gmCellIncY,
3346 gm.gmBlackBoxX, gm.gmBlackBoxY,
3347 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
3348
3349 IntUnLockFreeType();
3350
3351
3352 if (iFormat == GGO_METRICS)
3353 {
3354 DPRINT("GGO_METRICS Exit!\n");
3355 *pgm = gm;
3356 return 1; /* FIXME */
3357 }
3358
3359 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
3360 {
3361 DPRINT1("Loaded a bitmap\n");
3362 return GDI_ERROR;
3363 }
3364
3365 switch (iFormat)
3366 {
3367 case GGO_BITMAP:
3368 width = gm.gmBlackBoxX;
3369 height = gm.gmBlackBoxY;
3370 pitch = ((width + 31) >> 5) << 2;
3371 needed = pitch * height;
3372
3373 if (!pvBuf || !cjBuf) break;
3374 if (!needed) return GDI_ERROR; /* empty glyph */
3375 if (needed > cjBuf)
3376 return GDI_ERROR;
3377
3378 switch (ft_face->glyph->format)
3379 {
3380 case ft_glyph_format_bitmap:
3381 {
3382 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3383 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
3384 INT h = min( height, ft_face->glyph->bitmap.rows );
3385 while (h--)
3386 {
3387 RtlCopyMemory(dst, src, w);
3388 src += ft_face->glyph->bitmap.pitch;
3389 dst += pitch;
3390 }
3391 break;
3392 }
3393
3394 case ft_glyph_format_outline:
3395 ft_bitmap.width = width;
3396 ft_bitmap.rows = height;
3397 ft_bitmap.pitch = pitch;
3398 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
3399 ft_bitmap.buffer = pvBuf;
3400
3401 IntLockFreeType();
3402 if (needsTransform)
3403 {
3404 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3405 }
3406 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3407 /* Note: FreeType will only set 'black' bits for us. */
3408 RtlZeroMemory(pvBuf, needed);
3409 FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
3410 IntUnLockFreeType();
3411 break;
3412
3413 default:
3414 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3415 return GDI_ERROR;
3416 }
3417 break;
3418
3419 case GGO_GRAY2_BITMAP:
3420 case GGO_GRAY4_BITMAP:
3421 case GGO_GRAY8_BITMAP:
3422 {
3423 unsigned int mult, row, col;
3424 BYTE *start, *ptr;
3425
3426 width = gm.gmBlackBoxX;
3427 height = gm.gmBlackBoxY;
3428 pitch = (width + 3) / 4 * 4;
3429 needed = pitch * height;
3430
3431 if (!pvBuf || !cjBuf) break;
3432 if (!needed) return GDI_ERROR; /* empty glyph */
3433 if (needed > cjBuf)
3434 return GDI_ERROR;
3435
3436 switch (ft_face->glyph->format)
3437 {
3438 case ft_glyph_format_bitmap:
3439 {
3440 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3441 INT h = min( height, ft_face->glyph->bitmap.rows );
3442 INT x;
3443 while (h--)
3444 {
3445 for (x = 0; (UINT)x < pitch; x++)
3446 {
3447 if (x < ft_face->glyph->bitmap.width)
3448 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3449 else
3450 dst[x] = 0;
3451 }
3452 src += ft_face->glyph->bitmap.pitch;
3453 dst += pitch;
3454 }
3455 break;
3456 }
3457 case ft_glyph_format_outline:
3458 {
3459 ft_bitmap.width = width;
3460 ft_bitmap.rows = height;
3461 ft_bitmap.pitch = pitch;
3462 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3463 ft_bitmap.buffer = pvBuf;
3464
3465 IntLockFreeType();
3466 if (needsTransform)
3467 {
3468 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3469 }
3470 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3471 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
3472 FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
3473 IntUnLockFreeType();
3474
3475 if (iFormat == GGO_GRAY2_BITMAP)
3476 mult = 4;
3477 else if (iFormat == GGO_GRAY4_BITMAP)
3478 mult = 16;
3479 else if (iFormat == GGO_GRAY8_BITMAP)
3480 mult = 64;
3481 else
3482 {
3483 return GDI_ERROR;
3484 }
3485
3486 start = pvBuf;
3487 for (row = 0; row < height; row++)
3488 {
3489 ptr = start;
3490 for (col = 0; col < width; col++, ptr++)
3491 {
3492 *ptr = (((int)*ptr) * mult + 128) / 256;
3493 }
3494 start += pitch;
3495 }
3496
3497 break;
3498 }
3499 default:
3500 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3501 return GDI_ERROR;
3502 }
3503 }
3504
3505 case GGO_NATIVE:
3506 {
3507 FT_Outline *outline = &ft_face->glyph->outline;
3508
3509 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
3510
3511 IntLockFreeType();
3512 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
3513
3514 needed = get_native_glyph_outline(outline, cjBuf, NULL);
3515
3516 if (!pvBuf || !cjBuf)
3517 {
3518 IntUnLockFreeType();
3519 break;
3520 }
3521 if (needed > cjBuf)
3522 {
3523 IntUnLockFreeType();
3524 return GDI_ERROR;
3525 }
3526 get_native_glyph_outline(outline, cjBuf, pvBuf);
3527 IntUnLockFreeType();
3528 break;
3529 }
3530 case GGO_BEZIER:
3531 {
3532 FT_Outline *outline = &ft_face->glyph->outline;
3533 if (cjBuf == 0) pvBuf = NULL;
3534
3535 if (needsTransform && pvBuf)
3536 {
3537 IntLockFreeType();
3538 FT_Outline_Transform(outline, &transMat);
3539 IntUnLockFreeType();
3540 }
3541 needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
3542
3543 if (!pvBuf || !cjBuf)
3544 break;
3545 if (needed > cjBuf)
3546 return GDI_ERROR;
3547
3548 get_bezier_glyph_outline(outline, cjBuf, pvBuf);
3549 break;
3550 }
3551
3552 default:
3553 DPRINT1("Unsupported format %u\n", iFormat);
3554 return GDI_ERROR;
3555 }
3556
3557 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
3558 *pgm = gm;
3559 return needed;
3560 }
3561
3562 BOOL
3563 FASTCALL
3564 TextIntGetTextExtentPoint(PDC dc,
3565 PTEXTOBJ TextObj,
3566 LPCWSTR String,
3567 INT Count,
3568 ULONG MaxExtent,
3569 LPINT Fit,
3570 LPINT Dx,
3571 LPSIZE Size,
3572 FLONG fl)
3573 {
3574 PFONTGDI FontGDI;
3575 FT_Face face;
3576 FT_GlyphSlot glyph;
3577 FT_BitmapGlyph realglyph;
3578 INT error, glyph_index, i, previous;
3579 ULONGLONG TotalWidth = 0;
3580 BOOL use_kerning;
3581 FT_Render_Mode RenderMode;
3582 BOOLEAN Render;
3583 PMATRIX pmxWorldToDevice;
3584 LOGFONTW *plf;
3585 BOOL EmuBold, EmuItalic;
3586 LONG ascender, descender;
3587
3588 FontGDI = ObjToGDI(TextObj->Font, FONT);
3589
3590 face = FontGDI->SharedFace->Face;
3591 if (NULL != Fit)
3592 {
3593 *Fit = 0;
3594 }
3595
3596 IntLockFreeType();
3597
3598 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3599
3600 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3601 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
3602 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
3603
3604 Render = IntIsFontRenderingEnabled();
3605 if (Render)
3606 RenderMode = IntGetFontRenderMode(plf);
3607 else
3608 RenderMode = FT_RENDER_MODE_MONO;
3609
3610 /* Get the DC's world-to-device transformation matrix */
3611 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3612 FtSetCoordinateTransform(face, pmxWorldToDevice);
3613
3614 use_kerning = FT_HAS_KERNING(face);
3615 previous = 0;
3616
3617 for (i = 0; i < Count; i++)
3618 {
3619 if (fl & GTEF_INDICES)
3620 glyph_index = *String;
3621 else
3622 glyph_index = FT_Get_Char_Index(face, *String);
3623
3624 if (EmuBold || EmuItalic)
3625 realglyph = NULL;
3626 else
3627 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
3628 RenderMode, pmxWorldToDevice);
3629
3630 if (EmuBold || EmuItalic || !realglyph)
3631 {
3632 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3633 if (error)
3634 {
3635 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
3636 break;
3637 }
3638
3639 glyph = face->glyph;
3640 if (EmuBold || EmuItalic)
3641 {
3642 if (EmuBold)
3643 FT_GlyphSlot_Embolden(glyph);
3644 if (EmuItalic)
3645 FT_GlyphSlot_Oblique(glyph);
3646 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
3647 }
3648 else
3649 {
3650 realglyph = ftGdiGlyphCacheSet(face,
3651 glyph_index,
3652 plf->lfHeight,
3653 pmxWorldToDevice,
3654 glyph,
3655 RenderMode);
3656 }
3657
3658 if (!realglyph)
3659 {
3660 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3661 break;
3662 }
3663 }
3664
3665 /* Retrieve kerning distance */
3666 if (use_kerning && previous && glyph_index)
3667 {
3668 FT_Vector delta;
3669 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3670 TotalWidth += delta.x;
3671 }
3672
3673 TotalWidth += realglyph->root.advance.x >> 10;
3674
3675 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
3676 {
3677 *Fit = i + 1;
3678 }
3679 if (NULL != Dx)
3680 {
3681 Dx[i] = (TotalWidth + 32) >> 6;
3682 }
3683
3684 if (EmuBold || EmuItalic)
3685 {
3686 FT_Done_Glyph((FT_Glyph)realglyph);
3687 realglyph = NULL;
3688 }
3689
3690 previous = glyph_index;
3691 String++;
3692 }
3693 ascender = (face->size->metrics.ascender + 32) >> 6; /* Units above baseline */
3694 descender = (32 - face->size->metrics.descender) >> 6; /* Units below baseline */
3695 IntUnLockFreeType();
3696
3697 Size->cx = (TotalWidth + 32) >> 6;
3698 Size->cy = ascender + descender;
3699
3700 return TRUE;
3701 }
3702
3703
3704 INT
3705 FASTCALL
3706 ftGdiGetTextCharsetInfo(
3707 PDC Dc,
3708 LPFONTSIGNATURE lpSig,
3709 DWORD dwFlags)
3710 {
3711 PDC_ATTR pdcattr;
3712 UINT Ret = DEFAULT_CHARSET;
3713 INT i;
3714 HFONT hFont;
3715 PTEXTOBJ TextObj;
3716 PFONTGDI FontGdi;
3717 FONTSIGNATURE fs;
3718 TT_OS2 *pOS2;
3719 FT_Face Face;
3720 CHARSETINFO csi;
3721 DWORD cp, fs0;
3722 USHORT usACP, usOEM;
3723
3724 pdcattr = Dc->pdcattr;
3725 hFont = pdcattr->hlfntNew;
3726 TextObj = RealizeFontInit(hFont);
3727
3728 if (!TextObj)
3729 {
3730 EngSetLastError(ERROR_INVALID_HANDLE);
3731 return Ret;
3732 }
3733 FontGdi = ObjToGDI(TextObj->Font, FONT);
3734 Face = FontGdi->SharedFace->Face;
3735 TEXTOBJ_UnlockText(TextObj);
3736
3737 IntLockFreeType();
3738 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3739 IntUnLockFreeType();
3740 memset(&fs, 0, sizeof(FONTSIGNATURE));
3741 if (NULL != pOS2)
3742 {
3743 fs.fsCsb[0] = pOS2->ulCodePageRange1;
3744 fs.fsCsb[1] = pOS2->ulCodePageRange2;
3745 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3746 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3747 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3748 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3749 if (pOS2->version == 0)
3750 {
3751 FT_UInt dummy;
3752
3753 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
3754 fs.fsCsb[0] |= FS_LATIN1;
3755 else
3756 fs.fsCsb[0] |= FS_SYMBOL;
3757 }
3758 }
3759 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
3760 if (fs.fsCsb[0] == 0)
3761 { /* Let's see if we can find any interesting cmaps */
3762 for (i = 0; i < Face->num_charmaps; i++)
3763 {
3764 switch (Face->charmaps[i]->encoding)
3765 {
3766 case FT_ENCODING_UNICODE:
3767 case FT_ENCODING_APPLE_ROMAN:
3768 fs.fsCsb[0] |= FS_LATIN1;
3769 break;
3770 case FT_ENCODING_MS_SYMBOL:
3771 fs.fsCsb[0] |= FS_SYMBOL;
3772 break;
3773 default:
3774 break;
3775 }
3776 }
3777 }
3778 if (lpSig)
3779 {
3780 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
3781 }
3782
3783 RtlGetDefaultCodePage(&usACP, &usOEM);
3784 cp = usACP;
3785
3786 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
3787 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
3788 {
3789 DPRINT("Hit 1\n");
3790 Ret = csi.ciCharset;
3791 goto Exit;
3792 }
3793
3794 for (i = 0; i < MAXTCIINDEX; i++)
3795 {
3796 fs0 = 1L << i;
3797 if (fs.fsCsb[0] & fs0)
3798 {
3799 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
3800 {
3801 // *cp = csi.ciACP;
3802 DPRINT("Hit 2\n");
3803 Ret = csi.ciCharset;
3804 goto Exit;
3805 }
3806 else
3807 DPRINT1("TCI failing on %x\n", fs0);
3808 }
3809 }
3810 Exit:
3811 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
3812 return (MAKELONG(csi.ciACP, csi.ciCharset));
3813 }
3814
3815
3816 DWORD
3817 FASTCALL
3818 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
3819 {
3820 DWORD size = 0;
3821 DWORD num_ranges = 0;
3822 FT_Face face = Font->SharedFace->Face;
3823
3824 if (face->charmap->encoding == FT_ENCODING_UNICODE)
3825 {
3826 FT_UInt glyph_code = 0;
3827 FT_ULong char_code, char_code_prev;
3828
3829 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
3830
3831 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3832 face->num_glyphs, glyph_code, char_code);
3833
3834 if (!glyph_code) return 0;
3835
3836 if (glyphset)
3837 {
3838 glyphset->ranges[0].wcLow = (USHORT)char_code;
3839 glyphset->ranges[0].cGlyphs = 0;
3840 glyphset->cGlyphsSupported = 0;
3841 }
3842
3843 num_ranges = 1;
3844 while (glyph_code)
3845 {
3846 if (char_code < char_code_prev)
3847 {
3848 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
3849 return 0;
3850 }
3851 if (char_code - char_code_prev > 1)
3852 {
3853 num_ranges++;
3854 if (glyphset)
3855 {
3856 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
3857 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
3858 glyphset->cGlyphsSupported++;
3859 }
3860 }
3861 else if (glyphset)
3862 {
3863 glyphset->ranges[num_ranges - 1].cGlyphs++;
3864 glyphset->cGlyphsSupported++;
3865 }
3866 char_code_prev = char_code;
3867 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
3868 }
3869 }
3870 else
3871 DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
3872
3873 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
3874 if (glyphset)
3875 {
3876 glyphset->cbThis = size;
3877 glyphset->cRanges = num_ranges;
3878 glyphset->flAccel = 0;
3879 }
3880 return size;
3881 }
3882
3883
3884 BOOL
3885 FASTCALL
3886 ftGdiGetTextMetricsW(
3887 HDC hDC,
3888 PTMW_INTERNAL ptmwi)
3889 {
3890 PDC dc;
3891 PDC_ATTR pdcattr;
3892 PTEXTOBJ TextObj;
3893 PFONTGDI FontGDI;
3894 FT_Face Face;
3895 TT_OS2 *pOS2;
3896 TT_HoriHeader *pHori;
3897 FT_WinFNT_HeaderRec Win;
3898 ULONG Error;
3899 NTSTATUS Status = STATUS_SUCCESS;
3900 LOGFONTW *plf;
3901
3902 if (!ptmwi)
3903 {
3904 EngSetLastError(STATUS_INVALID_PARAMETER);
3905 return FALSE;
3906 }
3907
3908 if (!(dc = DC_LockDc(hDC)))
3909 {
3910 EngSetLastError(ERROR_INVALID_HANDLE);
3911 return FALSE;
3912 }
3913 pdcattr = dc->pdcattr;
3914 TextObj = RealizeFontInit(pdcattr->hlfntNew);
3915 if (NULL != TextObj)
3916 {
3917 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3918 FontGDI = ObjToGDI(TextObj->Font, FONT);
3919
3920 Face = FontGDI->SharedFace->Face;
3921 IntLockFreeType();
3922 Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
3923 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
3924 IntUnLockFreeType();
3925 if (0 != Error)
3926 {
3927 DPRINT1("Error in setting pixel sizes: %u\n", Error);
3928 Status = STATUS_UNSUCCESSFUL;
3929 }
3930 else
3931 {
3932 FT_Face Face = FontGDI->SharedFace->Face;
3933 Status = STATUS_SUCCESS;
3934
3935 IntLockFreeType();
3936 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3937 if (NULL == pOS2)
3938 {
3939 DPRINT1("Can't find OS/2 table - not TT font?\n");
3940 Status = STATUS_INTERNAL_ERROR;
3941 }
3942
3943 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
3944 if (NULL == pHori)
3945 {
3946 DPRINT1("Can't find HHEA table - not TT font?\n");
3947 Status = STATUS_INTERNAL_ERROR;
3948 }
3949
3950 Error = FT_Get_WinFNT_Header(Face, &Win);
3951
3952 IntUnLockFreeType();
3953
3954 if (NT_SUCCESS(Status))
3955 {
3956 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
3957
3958 /* FIXME: Fill Diff member */
3959 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
3960 }
3961 }
3962 TEXTOBJ_UnlockText(TextObj);
3963 }
3964 else
3965 {
3966 Status = STATUS_INVALID_HANDLE;
3967 }
3968 DC_UnlockDc(dc);
3969
3970 if (!NT_SUCCESS(Status))
3971 {
3972 SetLastNtError(Status);
3973 return FALSE;
3974 }
3975 return TRUE;
3976 }
3977
3978 DWORD
3979 FASTCALL
3980 ftGdiGetFontData(
3981 PFONTGDI FontGdi,
3982 DWORD Table,
3983 DWORD Offset,
3984 PVOID Buffer,
3985 DWORD Size)
3986 {
3987 DWORD Result = GDI_ERROR;
3988 FT_Face Face = FontGdi->SharedFace->Face;
3989
3990 IntLockFreeType();
3991
3992 if (FT_IS_SFNT(Face))
3993 {
3994 if (Table)
3995 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
3996 (Table << 8 & 0xFF0000);
3997
3998 if (!Buffer) Size = 0;
3999
4000 if (Buffer && Size)
4001 {
4002 FT_Error Error;
4003 FT_ULong Needed = 0;
4004
4005 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
4006
4007 if ( !Error && Needed < Size) Size = Needed;
4008 }
4009 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
4010 Result = Size;
4011 }
4012
4013 IntUnLockFreeType();
4014
4015 return Result;
4016 }
4017
4018 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
4019 static UINT
4020 GetFontPenalty(const LOGFONTW * LogFont,
4021 const OUTLINETEXTMETRICW * Otm,
4022 const char * style_name)
4023 {
4024 ULONG Penalty = 0;
4025 BYTE Byte;
4026 LONG Long;
4027 BOOL fNeedScaling = FALSE;
4028 const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
4029 const TEXTMETRICW * TM = &Otm->otmTextMetrics;
4030 WCHAR* ActualNameW;
4031
4032 ASSERT(Otm);
4033 ASSERT(LogFont);
4034
4035 /* FIXME: Aspect Penalty 30 */
4036 /* FIXME: IntSizeSynth Penalty 20 */
4037 /* FIXME: SmallPenalty Penalty 1 */
4038 /* FIXME: FaceNameSubst Penalty 500 */
4039
4040 Byte = LogFont->lfCharSet;
4041 if (Byte == DEFAULT_CHARSET)
4042 {
4043 if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0)
4044 {
4045 if (Byte == ANSI_CHARSET)
4046 {
4047 DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
4048 }
4049 /* We assume SYMBOL_CHARSET for "Marlett" font */
4050 Byte = SYMBOL_CHARSET;
4051 }
4052 }
4053
4054 if (Byte != TM->tmCharSet)
4055 {
4056 if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
4057 {
4058 /* CharSet Penalty 65000 */
4059 /* Requested charset does not match the candidate's. */
4060 Penalty += 65000;
4061 }
4062 else
4063 {
4064 if (UserCharSet != TM->tmCharSet)
4065 {
4066 /* UNDOCUMENTED */
4067 Penalty += 100;
4068 if (ANSI_CHARSET != TM->tmCharSet)
4069 {
4070 /* UNDOCUMENTED */
4071 Penalty += 100;
4072 }
4073 }
4074 }
4075 }
4076
4077 Byte = LogFont->lfOutPrecision;
4078 if (Byte == OUT_DEFAULT_PRECIS)
4079 Byte = OUT_OUTLINE_PRECIS; /* Is it OK? */
4080 switch (Byte)
4081 {
4082 case OUT_DEVICE_PRECIS:
4083 if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
4084 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
4085 {
4086 /* OutputPrecision Penalty 19000 */
4087 /* Requested OUT_STROKE_PRECIS, but the device can't do it
4088 or the candidate is not a vector font. */
4089 Penalty += 19000;
4090 }
4091 break;
4092 default:
4093 if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
4094 {
4095 /* OutputPrecision Penalty 19000 */
4096 /* Or OUT_STROKE_PRECIS not requested, and the candidate
4097 is a vector font that requires GDI support. */
4098 Penalty += 19000;
4099 }
4100 break;
4101 }
4102
4103 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4104 if (Byte == DEFAULT_PITCH)
4105 Byte = VARIABLE_PITCH;
4106 if (Byte == FIXED_PITCH)
4107 {
4108 if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
4109 {
4110 /* FixedPitch Penalty 15000 */
4111 /* Requested a fixed pitch font, but the candidate is a
4112 variable pitch font. */
4113 Penalty += 15000;
4114 }
4115 }
4116 if (Byte == VARIABLE_PITCH)
4117 {
4118 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4119 {
4120 /* PitchVariable Penalty 350 */
4121 /* Requested a variable pitch font, but the candidate is not a
4122 variable pitch font. */
4123 Penalty += 350;
4124 }
4125 }
4126
4127 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4128 if (Byte == DEFAULT_PITCH)
4129 {
4130 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4131 {
4132 /* DefaultPitchFixed Penalty 1 */
4133 /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
4134 Penalty += 1;
4135 }
4136 }
4137
4138 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
4139
4140 if (LogFont->lfFaceName[0])
4141 {
4142 BOOL Found = FALSE;
4143
4144 /* localized family name */
4145 if (!Found)
4146 {
4147 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4148 }
4149 /* localized full name */
4150 if (!Found)
4151 {
4152 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
4153 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4154 }
4155 if (!Found)
4156 {
4157 /* FaceName Penalty 10000 */
4158 /* Requested a face name, but the candidate's face name
4159 does not match. */
4160 Penalty += 10000;
4161 }
4162 }
4163
4164 Byte = (LogFont->lfPitchAndFamily & 0xF0);
4165 if (Byte != FF_DONTCARE)
4166 {
4167 if (Byte != (TM->tmPitchAndFamily & 0xF0))
4168 {
4169 /* Family Penalty 9000 */
4170 /* Requested a family, but the candidate's family is different. */
4171 Penalty += 9000;
4172 }
4173 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
4174 {
4175 /* FamilyUnknown Penalty 8000 */
4176 /* Requested a family, but the candidate has no family. */
4177 Penalty += 8000;
4178 }
4179 }
4180
4181 /* Is the candidate a non-vector font? */
4182 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4183 {
4184 /* Is lfHeight specified? */
4185 if (LogFont->lfHeight != 0)
4186 {
4187 if (labs(LogFont->lfHeight) < TM->tmHeight)
4188 {
4189 /* HeightBigger Penalty 600 */
4190 /* The candidate is a nonvector font and is bigger than the
4191 requested height. */
4192 Penalty += 600;
4193 /* HeightBiggerDifference Penalty 150 */
4194 /* The candidate is a raster font and is larger than the
4195 requested height. Penalty * height difference */
4196 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4197
4198 fNeedScaling = TRUE;
4199 }
4200 if (TM->tmHeight < labs(LogFont->lfHeight))
4201 {
4202 /* HeightSmaller Penalty 150 */
4203 /* The candidate is a raster font and is smaller than the
4204 requested height. Penalty * height difference */
4205 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4206
4207 fNeedScaling = TRUE;
4208 }
4209 }
4210 }
4211
4212 switch (LogFont->lfPitchAndFamily & 0xF0)
4213 {
4214 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4215 switch (TM->tmPitchAndFamily & 0xF0)
4216 {
4217 case FF_DECORATIVE: case FF_SCRIPT:
4218 /* FamilyUnlikely Penalty 50 */
4219 /* Requested a roman/modern/swiss family, but the
4220 candidate is decorative/script. */
4221 Penalty += 50;
4222 break;
4223 default:
4224 break;
4225 }
4226 break;
4227 case FF_DECORATIVE: case FF_SCRIPT:
4228 switch (TM->tmPitchAndFamily & 0xF0)
4229 {
4230 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4231 /* FamilyUnlikely Penalty 50 */
4232 /* Or requested decorative/script, and the candidate is
4233 roman/modern/swiss. */
4234 Penalty += 50;
4235 break;
4236 default:
4237 break;
4238 }
4239 default:
4240 break;
4241 }
4242
4243 if (LogFont->lfWidth != 0)
4244 {
4245 if (LogFont->lfWidth != TM->tmAveCharWidth)
4246 {
4247 /* Width Penalty 50 */
4248 /* Requested a nonzero width, but the candidate's width
4249 doesn't match. Penalty * width difference */
4250 Penalty += 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth);
4251
4252 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4253 fNeedScaling = TRUE;
4254 }
4255 }
4256
4257 if (fNeedScaling)
4258 {
4259 /* SizeSynth Penalty 50 */
4260 /* The candidate is a raster font that needs scaling by GDI. */
4261 Penalty += 50;
4262 }
4263
4264 if (!!LogFont->lfItalic != !!TM->tmItalic)
4265 {
4266 if (!LogFont->lfItalic && ItalicFromStyle(style_name))
4267 {
4268 /* Italic Penalty 4 */
4269 /* Requested font and candidate font do not agree on italic status,
4270 and the desired result cannot be simulated. */
4271 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
4272 Penalty += 40;
4273 }
4274 else if (LogFont->lfItalic && !ItalicFromStyle(style_name))
4275 {
4276 /* ItalicSim Penalty 1 */
4277 /* Requested italic font but the candidate is not italic,
4278 although italics can be simulated. */
4279 Penalty += 1;
4280 }
4281 }
4282
4283 if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
4284 {
4285 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
4286 {
4287 /* NotTrueType Penalty 4 */
4288 /* Requested OUT_TT_PRECIS, but the candidate is not a
4289 TrueType font. */
4290 Penalty += 4;
4291 }
4292 }
4293
4294 Long = LogFont->lfWeight;
4295 if (LogFont->lfWeight == FW_DONTCARE)
4296 Long = FW_NORMAL;
4297 if (Long != TM->tmWeight)
4298 {
4299 /* Weight Penalty 3 */
4300 /* The candidate's weight does not match the requested weight.
4301 Penalty * (weight difference/10) */
4302 Penalty += 3 * (labs(Long - TM->tmWeight) / 10);
4303 }
4304
4305 if (!LogFont->lfUnderline && TM->tmUnderlined)
4306 {
4307 /* Underline Penalty 3 */
4308 /* Requested font has no underline, but the candidate is
4309 underlined. */
4310 Penalty += 3;
4311 }
4312
4313 if (!LogFont->lfStrikeOut && TM->tmStruckOut)
4314 {
4315 /* StrikeOut Penalty 3 */
4316 /* Requested font has no strike-out, but the candidate is
4317 struck out. */
4318 Penalty += 3;
4319 }
4320
4321 /* Is the candidate a non-vector font? */
4322 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4323 {
4324 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
4325 {
4326 /* VectorHeightSmaller Penalty 2 */
4327 /* Candidate is a vector font that is smaller than the
4328 requested height. Penalty * height difference */
4329 Penalty += 2 * labs(TM->tmHeight - LogFont->lfHeight);
4330 }
4331 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
4332 {
4333 /* VectorHeightBigger Penalty 1 */
4334 /* Candidate is a vector font that is bigger than the
4335 requested height. Penalty * height difference */
4336 Penalty += 1 * labs(TM->tmHeight - LogFont->lfHeight);
4337 }
4338 }
4339
4340 if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
4341 {
4342 /* DeviceFavor Penalty 2 */
4343 /* Extra penalty for all nondevice fonts. */
4344 Penalty += 2;
4345 }
4346
4347 if (Penalty < 200)
4348 {
4349 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
4350 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
4351 "tmCharSet:%d, tmWeight:%ld\n",
4352 Penalty, LogFont->lfFaceName, ActualNameW,
4353 LogFont->lfCharSet, LogFont->lfWeight,
4354 TM->tmCharSet, TM->tmWeight);
4355 }
4356
4357 return Penalty; /* success */
4358 }
4359
4360 static __inline VOID
4361 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
4362 const LOGFONTW *LogFont,
4363 const PLIST_ENTRY Head)
4364 {
4365 ULONG Penalty;
4366 PLIST_ENTRY Entry;
4367 PFONT_ENTRY CurrentEntry;
4368 FONTGDI *FontGDI;
4369 OUTLINETEXTMETRICW *Otm = NULL;
4370 UINT OtmSize, OldOtmSize = 0;
4371 FT_Face Face;
4372
4373 ASSERT(FontObj);
4374 ASSERT(MatchPenalty);
4375 ASSERT(LogFont);
4376 ASSERT(Head);
4377
4378 /* Start with a pretty big buffer */
4379 OldOtmSize = 0x200;
4380 Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
4381
4382 /* get the FontObj of lowest penalty */
4383 Entry = Head->Flink;
4384 while (Entry != Head)
4385 {
4386 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
4387 Entry = Entry->Flink;
4388
4389 FontGDI = CurrentEntry->Font;
4390 ASSERT(FontGDI);
4391 Face = FontGDI->SharedFace->Face;
4392
4393 /* get text metrics */
4394 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4395 if (OtmSize > OldOtmSize)
4396 {
4397 if (Otm)
4398 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4399 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
4400 }
4401
4402 /* update FontObj if lowest penalty */
4403 if (Otm)
4404 {
4405 OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
4406 if (!OtmSize)
4407 continue;
4408
4409 OldOtmSize = OtmSize;
4410
4411 Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
4412 if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
4413 {
4414 *FontObj = GDIToObj(FontGDI, FONT);
4415 *MatchPenalty = Penalty;
4416 }
4417 }
4418 }
4419
4420 if (Otm)
4421 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4422 }
4423
4424 static
4425 VOID
4426 FASTCALL
4427 IntFontType(PFONTGDI Font)
4428 {
4429 PS_FontInfoRec psfInfo;
4430 FT_ULong tmp_size = 0;
4431 FT_Face Face = Font->SharedFace->Face;
4432
4433 if (FT_HAS_MULTIPLE_MASTERS(Face))
4434 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
4435 if (FT_HAS_VERTICAL(Face))
4436 Font->FontObj.flFontType |= FO_VERT_FACE;
4437 if (!FT_IS_SCALABLE(Face))
4438 Font->FontObj.flFontType |= FO_TYPE_RASTER;
4439 if (FT_IS_SFNT(Face))
4440 {
4441 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
4442 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
4443 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4444 }
4445 if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
4446 {
4447 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4448 }
4449 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
4450 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
4451 {
4452 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
4453 }
4454 }
4455
4456 NTSTATUS
4457 FASTCALL
4458 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
4459 {
4460 NTSTATUS Status = STATUS_SUCCESS;
4461 PTEXTOBJ TextObj;
4462 PPROCESSINFO Win32Process;
4463 ULONG MatchPenalty;
4464 LOGFONTW *pLogFont;
4465 LOGFONTW SubstitutedLogFont;
4466 FT_Face Face;
4467
4468 if (!pTextObj)
4469 {
4470 TextObj = TEXTOBJ_LockText(FontHandle);
4471 if (NULL == TextObj)
4472 {
4473 return STATUS_INVALID_HANDLE;
4474 }
4475
4476 if (TextObj->fl & TEXTOBJECT_INIT)
4477 {
4478 TEXTOBJ_UnlockText(TextObj);
4479 return STATUS_SUCCESS;
4480 }
4481 }
4482 else
4483 {
4484 TextObj = pTextObj;
4485 }
4486
4487 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4488
4489 /* substitute */
4490 SubstitutedLogFont = *pLogFont;
4491 DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
4492 SubstituteFontRecurse(&SubstitutedLogFont);
4493 DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
4494
4495 MatchPenalty = 0xFFFFFFFF;
4496 TextObj->Font = NULL;
4497
4498 Win32Process = PsGetCurrentProcessWin32Process();
4499
4500 /* Search private fonts */
4501 IntLockProcessPrivateFonts(Win32Process);
4502 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4503 &Win32Process->PrivateFontListHead);
4504 IntUnLockProcessPrivateFonts(Win32Process);
4505
4506 /* Search system fonts */
4507 IntLockGlobalFonts();
4508 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4509 &g_FontListHead);
4510 IntUnLockGlobalFonts();
4511
4512 if (NULL == TextObj->Font)
4513 {
4514 DPRINT1("Request font %S not found, no fonts loaded at all\n",
4515 pLogFont->lfFaceName);
4516 Status = STATUS_NOT_FOUND;
4517 }
4518 else
4519 {
4520 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
4521 // Need hdev, when freetype is loaded need to create DEVOBJ for
4522 // Consumer and Producer.
4523 TextObj->Font->iUniq = 1; // Now it can be cached.
4524 IntFontType(FontGdi);
4525 FontGdi->flType = TextObj->Font->flFontType;
4526 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
4527 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
4528 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
4529 if (pLogFont->lfWeight != FW_DONTCARE)
4530 FontGdi->RequestWeight = pLogFont->lfWeight;
4531 else
4532 FontGdi->RequestWeight = FW_NORMAL;
4533
4534 Face = FontGdi->SharedFace->Face;
4535
4536 //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name);
4537
4538 if (!FontGdi->OriginalItalic)
4539 FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name);
4540
4541 TextObj->fl |= TEXTOBJECT_INIT;
4542 Status = STATUS_SUCCESS;
4543 }
4544
4545 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
4546
4547 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
4548
4549 return Status;
4550 }
4551
4552
4553 static
4554 BOOL
4555 FASTCALL
4556 IntGetFullFileName(
4557 POBJECT_NAME_INFORMATION NameInfo,
4558 ULONG Size,
4559 PUNICODE_STRING FileName)
4560 {
4561 NTSTATUS Status;
4562 OBJECT_ATTRIBUTES ObjectAttributes;
4563 HANDLE hFile;
4564 IO_STATUS_BLOCK IoStatusBlock;
4565 ULONG Desired;
4566
4567 InitializeObjectAttributes(&ObjectAttributes,
4568 FileName,
4569 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
4570 NULL,
4571 NULL);
4572
4573 Status = ZwOpenFile(
4574 &hFile,
4575 0, // FILE_READ_ATTRIBUTES,
4576 &ObjectAttributes,
4577 &IoStatusBlock,
4578 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4579 0);
4580
4581 if (!NT_SUCCESS(Status))
4582 {
4583 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
4584 return FALSE;
4585 }
4586
4587 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
4588 ZwClose(hFile);
4589 if (!NT_SUCCESS(Status))
4590 {
4591 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
4592 return FALSE;
4593 }
4594
4595 return TRUE;
4596 }
4597
4598 static BOOL
4599 EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2)
4600 {
4601 const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
4602 const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
4603 const LOGFONTW *plf1 = &pLog1->elfLogFont;
4604 const LOGFONTW *plf2 = &pLog2->elfLogFont;
4605
4606 if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0)
4607 {
4608 return FALSE;
4609 }
4610
4611 if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0)
4612 {
4613 return FALSE;
4614 }
4615
4616 return TRUE;
4617 }
4618
4619 static VOID
4620 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
4621 {
4622 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
4623 if (FamInfo->EnumLogFontEx.elfStyle[0] &&
4624 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
4625 {
4626 wcscat(psz, L" ");
4627 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
4628 }
4629 }
4630
4631 BOOL
4632 FASTCALL
4633 IntGdiGetFontResourceInfo(
4634 PUNICODE_STRING FileName,
4635 PVOID pBuffer,
4636 DWORD *pdwBytes,
4637 DWORD dwType)
4638 {
4639 UNICODE_STRING EntryFileName;
4640 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
4641 PLIST_ENTRY ListEntry;
4642 PFONT_ENTRY FontEntry;
4643 ULONG Size, i, Count;
4644 LPBYTE pbBuffer;
4645 BOOL IsEqual;
4646 FONTFAMILYINFO *FamInfo;
4647 const ULONG MaxFamInfo = 64;
4648 BOOL bSuccess;
4649
4650 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
4651
4652 /* Create buffer for full path name */
4653 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
4654 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4655 if (!NameInfo1)
4656 {
4657 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4658 return FALSE;
4659 }
4660
4661 /* Get the full path name */
4662 if (!IntGetFullFileName(NameInfo1, Size, FileName))
4663 {
4664 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4665 return FALSE;
4666 }
4667
4668 /* Create a buffer for the entries' names */
4669 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4670 if (!NameInfo2)
4671 {
4672 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4673 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4674 return FALSE;
4675 }
4676
4677 FamInfo = ExAllocatePoolWithTag(PagedPool,
4678 sizeof(FONTFAMILYINFO) * MaxFamInfo,
4679 TAG_FINF);
4680 if (!FamInfo)
4681 {
4682 ExFreePoolWithTag(NameInfo2, TAG_FINF);
4683 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4684 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4685 return FALSE;
4686 }
4687 /* Try to find the pathname in the global font list */
4688 Count = 0;
4689 IntLockGlobalFonts();
4690 for (ListEntry = g_FontListHead.Flink; ListEntry != &g_FontListHead;
4691 ListEntry = ListEntry->Flink)
4692 {
4693 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
4694 if (FontEntry->Font->Filename == NULL)
4695 continue;
4696
4697 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
4698 if (!IntGetFullFileName(NameInfo2, Size, &EntryFileName))
4699 continue;
4700
4701 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
4702 continue;
4703
4704 IsEqual = FALSE;
4705 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
4706 NULL, FontEntry->Font);
4707 for (i = 0; i < Count; ++i)
4708 {
4709 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
4710 {
4711 IsEqual = TRUE;
4712 break;
4713 }
4714 }
4715 if (!IsEqual)
4716 {
4717 /* Found */
4718 ++Count;
4719 if (Count >= MaxFamInfo)
4720 break;
4721 }
4722 }
4723 IntUnLockGlobalFonts();
4724
4725 /* Free the buffers */
4726 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4727 ExFreePool(NameInfo2);
4728
4729 if (Count == 0 && dwType != 5)
4730 {
4731 /* Font could not be found in system table
4732 dwType == 5 will still handle this */
4733 ExFreePoolWithTag(FamInfo, TAG_FINF);
4734 return FALSE;
4735 }
4736
4737 bSuccess = FALSE;
4738 switch (dwType)
4739 {
4740 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
4741 Size = sizeof(DWORD);
4742 if (*pdwBytes == 0)
4743 {
4744 *pdwBytes = Size;
4745 bSuccess = TRUE;
4746 }
4747 else if (pBuffer)
4748 {
4749 if (*pdwBytes >= Size)
4750 {
4751 *(DWORD*)pBuffer = Count;
4752 }
4753 *pdwBytes = Size;
4754 bSuccess = TRUE;
4755 }
4756 break;
4757
4758 case 1: /* copy the font title */
4759 /* calculate the required size */
4760 Size = 0;
4761 Size += wcslen(FamInfo[0].EnumLogFontEx.elfLogFont.lfFaceName);
4762 if (FamInfo[0].EnumLogFontEx.elfStyle[0] &&
4763 _wcsicmp(FamInfo[0].EnumLogFontEx.elfStyle, L"Regular") != 0)
4764 {
4765 Size += 1 + wcslen(FamInfo[0].EnumLogFontEx.elfStyle);
4766 }
4767 for (i = 1; i < Count; ++i)
4768 {
4769 Size += 3; /* " & " */
4770 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
4771 if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
4772 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
4773 {
4774 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
4775 }
4776 }
4777 Size += 2; /* "\0\0" */
4778 Size *= sizeof(WCHAR);
4779
4780 if (*pdwBytes == 0)
4781 {
4782 *pdwBytes = Size;
4783 bSuccess = TRUE;
4784 }
4785 else if (pBuffer)
4786 {
4787 if (*pdwBytes >= Size)
4788 {
4789 /* store font title to buffer */
4790 WCHAR *psz = pBuffer;
4791 *psz = 0;
4792 IntAddNameFromFamInfo(psz, &FamInfo[0]);
4793 for (i = 1; i < Count; ++i)
4794 {
4795 wcscat(psz, L" & ");
4796 IntAddNameFromFamInfo(psz, &FamInfo[i]);
4797 }
4798 psz[wcslen(psz) + 1] = UNICODE_NULL;
4799 *pdwBytes = Size;
4800 bSuccess = TRUE;
4801 }
4802 else
4803 {
4804 *pdwBytes = 1024; /* this is confirmed value */
4805 }
4806 }
4807 break;
4808
4809 case 2: /* Copy an array of LOGFONTW */
4810 Size = Count * sizeof(LOGFONTW);
4811 if (*pdwBytes == 0)
4812 {
4813 *pdwBytes = Size;
4814 bSuccess = TRUE;
4815 }
4816 else if (pBuffer)
4817 {
4818 if (*pdwBytes >= Size)
4819 {
4820 pbBuffer = (LPBYTE)pBuffer;
4821 for (i = 0; i < Count; ++i)
4822 {
4823 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
4824 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
4825 pbBuffer += sizeof(LOGFONTW);
4826 }
4827 }
4828 *pdwBytes = Size;
4829 bSuccess = TRUE;
4830 }
4831 else
4832 {
4833 *pdwBytes = 1024; /* this is confirmed value */
4834 }
4835 break;
4836
4837 case 3:
4838 Size = sizeof(DWORD);
4839 if (*pdwBytes == 0)
4840 {
4841 *pdwBytes = Size;
4842 bSuccess = TRUE;
4843 }
4844 else if (pBuffer)
4845 {
4846 if (*pdwBytes >= Size)
4847 {
4848 /* FIXME: What exactly is copied here? */
4849 *(DWORD*)pBuffer = 1;
4850 }
4851 *pdwBytes = Size;
4852 bSuccess = TRUE;
4853 }
4854 break;
4855
4856 case 4: /* full file path */
4857 if (FileName->Length >= 4 * sizeof(WCHAR))
4858 {
4859 /* The beginning of FileName is \??\ */
4860 LPWSTR pch = FileName->Buffer + 4;
4861 DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
4862
4863 Size = Length + sizeof(WCHAR);
4864 if (*pdwBytes == 0)
4865 {
4866 *pdwBytes = Size;
4867 bSuccess = TRUE;
4868 }
4869 else if (pBuffer)
4870 {
4871 if (*pdwBytes >= Size)
4872 {
4873 RtlCopyMemory(pBuffer, pch, Size);
4874 }
4875 *pdwBytes = Size;
4876 bSuccess = TRUE;
4877 }
4878 }
4879 break;
4880
4881 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
4882 Size = sizeof(BOOL);
4883 if (*pdwBytes == 0)
4884 {
4885 *pdwBytes = Size;
4886 bSuccess = TRUE;
4887 }
4888 else if (pBuffer)
4889 {
4890 if (*pdwBytes >= Size)
4891 {
4892 *(BOOL*)pBuffer = Count == 0;
4893 }
4894 *pdwBytes = Size;
4895 bSuccess = TRUE;
4896 }
4897 break;
4898 }
4899 ExFreePoolWithTag(FamInfo, TAG_FINF);
4900
4901 return bSuccess;
4902 }
4903
4904
4905 BOOL
4906 FASTCALL
4907 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
4908 {
4909 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
4910 Info->iTechnology = RI_TECH_BITMAP;
4911 else
4912 {
4913 if (FT_IS_SCALABLE(Font->SharedFace->Face))
4914 Info->iTechnology = RI_TECH_SCALABLE;
4915 else
4916 Info->iTechnology = RI_TECH_FIXED;
4917 }
4918 Info->iUniq = Font->FontObj.iUniq;
4919 Info->dwUnknown = -1;
4920 return TRUE;
4921 }
4922
4923
4924 DWORD
4925 FASTCALL
4926 ftGdiGetKerningPairs( PFONTGDI Font,
4927 DWORD cPairs,
4928 LPKERNINGPAIR pKerningPair)
4929 {
4930 DWORD Count = 0;
4931 INT i = 0;
4932 FT_Face face = Font->SharedFace->Face;
4933
4934 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
4935 {
4936 FT_UInt previous_index = 0, glyph_index = 0;
4937 FT_ULong char_code, char_previous;
4938 FT_Vector delta;
4939
4940 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
4941
4942 IntLockFreeType();
4943
4944 while (glyph_index)
4945 {
4946 if (previous_index && glyph_index)
4947 {
4948 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
4949
4950 if (pKerningPair && cPairs)
4951 {
4952 pKerningPair[i].wFirst = char_previous;
4953 pKerningPair[i].wSecond = char_code;
4954 pKerningPair[i].iKernAmount = delta.x;
4955 i++;
4956 if (i == cPairs) break;
4957 }
4958 Count++;
4959 }
4960 previous_index = glyph_index;
4961 char_previous = char_code;
4962 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
4963 }
4964 IntUnLockFreeType();
4965 }
4966 return Count;
4967 }
4968
4969
4970 ///////////////////////////////////////////////////////////////////////////
4971 //
4972 // Functions needing sorting.
4973 //
4974 ///////////////////////////////////////////////////////////////////////////
4975 int APIENTRY
4976 NtGdiGetFontFamilyInfo(HDC Dc,
4977 LPLOGFONTW UnsafeLogFont,
4978 PFONTFAMILYINFO UnsafeInfo,
4979 DWORD Size)
4980 {
4981 NTSTATUS Status;
4982 LOGFONTW LogFont;
4983 PFONTFAMILYINFO Info;
4984 DWORD Count;
4985 PPROCESSINFO Win32Process;
4986
4987 /* Make a safe copy */
4988 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
4989 if (! NT_SUCCESS(Status))
4990 {
4991 EngSetLastError(ERROR_INVALID_PARAMETER);
4992 return -1;
4993 }
4994
4995 /* Allocate space for a safe copy */
4996 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT);
4997 if (NULL == Info)
4998 {
4999 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5000 return -1;
5001 }
5002
5003 /* Enumerate font families in the global list */
5004 IntLockGlobalFonts();
5005 Count = 0;
5006 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &g_FontListHead) )
5007 {
5008 IntUnLockGlobalFonts();
5009 ExFreePoolWithTag(Info, GDITAG_TEXT);
5010 return -1;
5011 }
5012 IntUnLockGlobalFonts();
5013
5014 /* Enumerate font families in the process local list */
5015 Win32Process = PsGetCurrentProcessWin32Process();
5016 IntLockProcessPrivateFonts(Win32Process);
5017 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
5018 &Win32Process->PrivateFontListHead))
5019 {
5020 IntUnLockProcessPrivateFonts(Win32Process);
5021 ExFreePoolWithTag(Info, GDITAG_TEXT);
5022 return -1;
5023 }
5024 IntUnLockProcessPrivateFonts(Win32Process);
5025
5026 /* Enumerate font families in the registry */
5027 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
5028 {
5029 ExFreePoolWithTag(Info, GDITAG_TEXT);
5030 return -1;
5031 }
5032
5033 /* Return data to caller */
5034 if (0 != Count)
5035 {
5036 Status = MmCopyToCaller(UnsafeInfo, Info,
5037 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
5038 if (! NT_SUCCESS(Status))
5039 {
5040 ExFreePoolWithTag(Info, GDITAG_TEXT);
5041 EngSetLastError(ERROR_INVALID_PARAMETER);
5042 return -1;
5043 }
5044 }
5045
5046 ExFreePoolWithTag(Info, GDITAG_TEXT);
5047
5048 return Count;
5049 }
5050
5051 FORCEINLINE
5052 LONG
5053 ScaleLong(LONG lValue, PFLOATOBJ pef)
5054 {
5055 FLOATOBJ efTemp;
5056
5057 /* Check if we have scaling different from 1 */
5058 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
5059 {
5060 /* Need to multiply */
5061 FLOATOBJ_SetLong(&efTemp, lValue);
5062 FLOATOBJ_Mul(&efTemp, pef);
5063 lValue = FLOATOBJ_GetLong(&efTemp);
5064 }
5065
5066 return lValue;
5067 }
5068
5069 BOOL
5070 APIENTRY
5071 GreExtTextOutW(
5072 IN HDC hDC,
5073 IN INT XStart,
5074 IN INT YStart,
5075 IN UINT fuOptions,
5076 IN OPTIONAL PRECTL lprc,
5077 IN LPCWSTR String,
5078 IN INT Count,
5079 IN OPTIONAL LPINT Dx,
5080 IN DWORD dwCodePage)
5081 {
5082 /*
5083 * FIXME:
5084 * Call EngTextOut, which does the real work (calling DrvTextOut where
5085 * appropriate)
5086 */
5087
5088 DC *dc;
5089 PDC_ATTR pdcattr;
5090 SURFOBJ *SurfObj;
5091 SURFACE *psurf = NULL;
5092 int error, glyph_index, i;
5093 FT_Face face;
5094 FT_GlyphSlot glyph;
5095 FT_BitmapGlyph realglyph;
5096 LONGLONG TextLeft, RealXStart;
5097 ULONG TextTop, previous, BackgroundLeft;
5098 FT_Bool use_kerning;
5099 RECTL DestRect, MaskRect;
5100 POINTL SourcePoint, BrushOrigin;
5101 HBITMAP HSourceGlyph;
5102 SURFOBJ *SourceGlyphSurf;
5103 SIZEL bitSize;
5104 INT yoff;
5105 FONTOBJ *FontObj;
5106 PFONTGDI FontGDI;
5107 PTEXTOBJ TextObj = NULL;
5108 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
5109 FT_Render_Mode RenderMode;
5110 BOOLEAN Render;
5111 POINT Start;
5112 BOOL DoBreak = FALSE;
5113 USHORT DxShift;
5114 PMATRIX pmxWorldToDevice;
5115 LONG fixAscender, fixDescender;
5116 FLOATOBJ Scale;
5117 LOGFONTW *plf;
5118 BOOL EmuBold, EmuItalic;
5119 int thickness;
5120 BOOL bResult;
5121
5122 /* Check if String is valid */
5123 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
5124 {
5125 EngSetLastError(ERROR_INVALID_PARAMETER);
5126 return FALSE;
5127 }
5128
5129 /* NOTE: This function locks the screen DC, so it must never be called
5130 with a DC already locked */
5131 Render = IntIsFontRenderingEnabled();
5132
5133 // TODO: Write test-cases to exactly match real Windows in different
5134 // bad parameters (e.g. does Windows check the DC or the RECT first?).
5135 dc = DC_LockDc(hDC);
5136 if (!dc)
5137 {
5138 EngSetLastError(ERROR_INVALID_HANDLE);
5139 return FALSE;
5140 }
5141
5142 if (PATH_IsPathOpen(dc->dclevel))
5143 {
5144 bResult = PATH_ExtTextOut(dc,
5145 XStart,
5146 YStart,
5147 fuOptions,
5148 (const RECTL *)lprc,
5149 String,
5150 Count,
5151 (const INT *)Dx);
5152 DC_UnlockDc(dc);
5153 return bResult;
5154 }
5155
5156 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
5157
5158 if (!dc->dclevel.pSurface)
5159 {
5160 /* Memory DC with no surface selected */
5161 bResult = TRUE;
5162 goto Cleanup;
5163 }
5164
5165 pdcattr = dc->pdcattr;
5166
5167 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
5168 {
5169 IntLPtoDP(dc, (POINT *)lprc, 2);
5170 }
5171
5172 if (pdcattr->lTextAlign & TA_UPDATECP)
5173 {
5174 Start.x = pdcattr->ptlCurrent.x;
5175 Start.y = pdcattr->ptlCurrent.y;
5176 } else {
5177 Start.x = XStart;
5178 Start.y = YStart;
5179 }
5180
5181 IntLPtoDP(dc, &Start, 1);
5182 RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
5183 YStart = Start.y + dc->ptlDCOrig.y;
5184
5185 SourcePoint.x = 0;
5186 SourcePoint.y = 0;
5187 MaskRect.left = 0;
5188 MaskRect.top = 0;
5189 BrushOrigin.x = 0;
5190 BrushOrigin.y = 0;
5191
5192 if ((fuOptions & ETO_OPAQUE) && lprc)
5193 {
5194 DestRect.left = lprc->left;
5195 DestRect.top = lprc->top;
5196 DestRect.right = lprc->right;
5197 DestRect.bottom = lprc->bottom;
5198
5199 DestRect.left += dc->ptlDCOrig.x;
5200 DestRect.top += dc->ptlDCOrig.y;
5201 DestRect.right += dc->ptlDCOrig.x;
5202 DestRect.bottom += dc->ptlDCOrig.y;
5203
5204 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5205 {
5206 IntUpdateBoundsRect(dc, &DestRect);
5207 }
5208
5209 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5210 DC_vUpdateBackgroundBrush(dc);
5211 if (dc->dctype == DCTYPE_DIRECT)
5212 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5213
5214 psurf = dc->dclevel.pSurface;
5215 IntEngBitBlt(
5216 &psurf->SurfObj,
5217 NULL,
5218 NULL,
5219 (CLIPOBJ *)&dc->co,
5220 NULL,
5221 &DestRect,
5222 &SourcePoint,
5223 &SourcePoint,
5224 &dc->eboBackground.BrushObject,
5225 &BrushOrigin,
5226 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5227
5228 if (dc->dctype == DCTYPE_DIRECT)
5229 MouseSafetyOnDrawEnd(dc->ppdev);
5230
5231 fuOptions &= ~ETO_OPAQUE;
5232 }
5233 else
5234 {
5235 if (pdcattr->jBkMode == OPAQUE)
5236 {
5237 fuOptions |= ETO_OPAQUE;
5238 }
5239 }
5240
5241 TextObj = RealizeFontInit(pdcattr->hlfntNew);
5242 if (TextObj == NULL)
5243 {
5244 bResult = FALSE;
5245 goto Cleanup;
5246 }
5247
5248 FontObj = TextObj->Font;
5249 ASSERT(FontObj);
5250 FontGDI = ObjToGDI(FontObj, FONT);
5251 ASSERT(FontGDI);
5252
5253 IntLockFreeType();
5254 face = FontGDI->SharedFace->Face;
5255
5256 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5257 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
5258 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
5259
5260 if (Render)
5261 RenderMode = IntGetFontRenderMode(plf);
5262 else
5263 RenderMode = FT_RENDER_MODE_MONO;
5264
5265 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
5266 {
5267 IntUnLockFreeType();
5268 bResult = FALSE;
5269 goto Cleanup;
5270 }
5271
5272 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
5273 {
5274 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
5275 FtSetCoordinateTransform(face, pmxWorldToDevice);
5276
5277 fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
5278 fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
5279 }
5280 else
5281 {
5282 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
5283 FtSetCoordinateTransform(face, pmxWorldToDevice);
5284
5285 fixAscender = face->size->metrics.ascender;
5286 fixDescender = face->size->metrics.descender;
5287 }
5288
5289 /*
5290 * Process the vertical alignment and determine the yoff.
5291 */
5292
5293 if (pdcattr->lTextAlign & TA_BASELINE)
5294 yoff = 0;
5295 else if (pdcattr->lTextAlign & TA_BOTTOM)
5296 yoff = -fixDescender >> 6;
5297 else /* TA_TOP */
5298 yoff = fixAscender >> 6;
5299
5300 use_kerning = FT_HAS_KERNING(face);
5301 previous = 0;
5302
5303 /*
5304 * Process the horizontal alignment and modify XStart accordingly.
5305 */
5306 DxShift = fuOptions & ETO_PDY ? 1 : 0;
5307 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
5308 {
5309 ULONGLONG TextWidth = 0;
5310 LPCWSTR TempText = String;
5311 int iStart;
5312
5313 /*
5314 * Calculate width of the text.
5315 */
5316
5317 if (NULL != Dx)
5318 {
5319 iStart = Count < 2 ? 0 : Count - 2;
5320 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
5321 }
5322 else
5323 {
5324 iStart = 0;
5325 }
5326 TempText = String + iStart;
5327
5328 for (i = iStart; i < Count; i++)
5329 {
5330 if (fuOptions & ETO_GLYPH_INDEX)
5331 glyph_index = *TempText;
5332 else
5333 glyph_index = FT_Get_Char_Index(face, *TempText);
5334
5335 if (EmuBold || EmuItalic)
5336 realglyph = NULL;
5337 else
5338 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
5339 RenderMode, pmxWorldToDevice);
5340 if (!realglyph)
5341 {
5342 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5343 if (error)
5344 {
5345 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
5346 }
5347
5348 glyph = face->glyph;
5349 if (EmuBold || EmuItalic)
5350 {
5351 if (EmuBold)
5352 FT_GlyphSlot_Embolden(glyph);
5353 if (EmuItalic)
5354 FT_GlyphSlot_Oblique(glyph);
5355 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5356 }
5357 else
5358 {
5359 realglyph = ftGdiGlyphCacheSet(face,
5360 glyph_index,
5361 plf->lfHeight,
5362 pmxWorldToDevice,
5363 glyph,
5364 RenderMode);
5365 }
5366 if (!realglyph)
5367 {
5368 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5369 IntUnLockFreeType();
5370 goto Cleanup;
5371 }
5372
5373 }
5374 /* Retrieve kerning distance */
5375 if (use_kerning && previous && glyph_index)
5376 {
5377 FT_Vector delta;
5378 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5379 TextWidth += delta.x;
5380 }
5381
5382 TextWidth += realglyph->root.advance.x >> 10;
5383
5384 if (EmuBold || EmuItalic)
5385 {
5386 FT_Done_Glyph((FT_Glyph)realglyph);
5387 realglyph = NULL;
5388 }
5389
5390 previous = glyph_index;
5391 TempText++;
5392 }
5393
5394 previous = 0;
5395
5396 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
5397 {
5398 RealXStart -= TextWidth / 2;
5399 }
5400 else
5401 {
5402 RealXStart -= TextWidth;
5403 }
5404 }
5405
5406 psurf = dc->dclevel.pSurface;
5407 SurfObj = &psurf->SurfObj ;
5408
5409 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
5410 DC_vUpdateBackgroundBrush(dc) ;
5411
5412 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
5413 DC_vUpdateTextBrush(dc) ;
5414
5415 if (!face->units_per_EM)
5416 {
5417 thickness = 1;
5418 }
5419 else
5420 {
5421 thickness = face->underline_thickness *
5422 face->size->metrics.y_ppem / face->units_per_EM;
5423 if (thickness <= 0)
5424 thickness = 1;
5425 }
5426
5427 if ((fuOptions & ETO_OPAQUE) && plf->lfItalic)
5428 {
5429 /* Draw background */
5430 TextLeft = RealXStart;
5431 TextTop = YStart;
5432 BackgroundLeft = (RealXStart + 32) >> 6;
5433 for (i = 0; i < Count; ++i)
5434 {
5435 if (fuOptions & ETO_GLYPH_INDEX)
5436 glyph_index = String[i];
5437 else
5438 glyph_index = FT_Get_Char_Index(face, String[i]);
5439
5440 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5441 if (error)
5442 {
5443 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5444 IntUnLockFreeType();
5445 goto Cleanup;
5446 }
5447
5448 glyph = face->glyph;
5449 if (EmuBold)
5450 FT_GlyphSlot_Embolden(glyph);
5451 if (EmuItalic)
5452 FT_GlyphSlot_Oblique(glyph);
5453 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5454 if (!realglyph)
5455 {
5456 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5457 IntUnLockFreeType();
5458 goto Cleanup;
5459 }
5460
5461 /* retrieve kerning distance and move pen position */
5462 if (use_kerning && previous && glyph_index && NULL == Dx)
5463 {
5464 FT_Vector delta;
5465 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5466 TextLeft += delta.x;
5467 }
5468 DPRINT("TextLeft: %I64d\n", TextLeft);
5469 DPRINT("TextTop: %lu\n", TextTop);
5470 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5471
5472 DestRect.left = BackgroundLeft;
5473 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5474 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5475 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5476 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5477 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5478 {
5479 IntUpdateBoundsRect(dc, &DestRect);
5480 }
5481 IntEngBitBlt(
5482 &psurf->SurfObj,
5483 NULL,
5484 NULL,
5485 (CLIPOBJ *)&dc->co,
5486 NULL,
5487 &DestRect,
5488 &SourcePoint,
5489 &SourcePoint,
5490 &dc->eboBackground.BrushObject,
5491 &BrushOrigin,
5492 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5493 MouseSafetyOnDrawEnd(dc->ppdev);
5494 BackgroundLeft = DestRect.right;
5495
5496 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5497 DestRect.right = DestRect.left + realglyph->bitmap.width;
5498 DestRect.top = TextTop + yoff - realglyph->top;
5499 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5500
5501 bitSize.cx = realglyph->bitmap.width;
5502 bitSize.cy = realglyph->bitmap.rows;
5503 MaskRect.right = realglyph->bitmap.width;
5504 MaskRect.bottom = realglyph->bitmap.rows;
5505
5506 if (NULL == Dx)
5507 {
5508 TextLeft += realglyph->root.advance.x >> 10;
5509 DPRINT("New TextLeft: %I64d\n", TextLeft);
5510 }
5511 else
5512 {
5513 // FIXME this should probably be a matrix transform with TextTop as well.
5514 Scale = pdcattr->mxWorldToDevice.efM11;
5515 if (FLOATOBJ_Equal0(&Scale))
5516 FLOATOBJ_Set1(&Scale);
5517
5518 /* do the shift before multiplying to preserve precision */
5519 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5520 TextLeft += FLOATOBJ_GetLong(&Scale);
5521 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5522 }
5523
5524 if (DxShift)
5525 {
5526 TextTop -= Dx[2 * i + 1] << 6;
5527 }
5528
5529 previous = glyph_index;
5530
5531 if (EmuBold || EmuItalic)
5532 {
5533 FT_Done_Glyph((FT_Glyph)realglyph);
5534 realglyph = NULL;
5535 }
5536 }
5537 }
5538
5539 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
5540 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
5541
5542 /* Assume success */
5543 bResult = TRUE;
5544
5545 /*
5546 * The main rendering loop.
5547 */
5548 TextLeft = RealXStart;
5549 TextTop = YStart;
5550 BackgroundLeft = (RealXStart + 32) >> 6;
5551 for (i = 0; i < Count; ++i)
5552 {
5553 if (fuOptions & ETO_GLYPH_INDEX)
5554 glyph_index = String[i];
5555 else
5556 glyph_index = FT_Get_Char_Index(face, String[i]);
5557
5558 if (EmuBold || EmuItalic)
5559 realglyph = NULL;
5560 else
5561 realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
5562 RenderMode, pmxWorldToDevice);
5563 if (!realglyph)
5564 {
5565 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5566 if (error)
5567 {
5568 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5569 bResult = FALSE;
5570 break;
5571 }
5572
5573 glyph = face->glyph;
5574 if (EmuBold || EmuItalic)
5575 {
5576 if (EmuBold)
5577 FT_GlyphSlot_Embolden(glyph);
5578 if (EmuItalic)
5579 FT_GlyphSlot_Oblique(glyph);
5580 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5581 }
5582 else
5583 {
5584 realglyph = ftGdiGlyphCacheSet(face,
5585 glyph_index,
5586 plf->lfHeight,
5587 pmxWorldToDevice,
5588 glyph,
5589 RenderMode);
5590 }
5591 if (!realglyph)
5592 {
5593 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5594 bResult = FALSE;
5595 break;
5596 }
5597 }
5598
5599 /* retrieve kerning distance and move pen position */
5600 if (use_kerning && previous && glyph_index && NULL == Dx)
5601 {
5602 FT_Vector delta;
5603 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5604 TextLeft += delta.x;
5605 }
5606 DPRINT("TextLeft: %I64d\n", TextLeft);
5607 DPRINT("TextTop: %lu\n", TextTop);
5608 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5609
5610 if ((fuOptions & ETO_OPAQUE) && !plf->lfItalic)
5611 {
5612 DestRect.left = BackgroundLeft;
5613 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5614 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5615 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5616
5617 if (dc->dctype == DCTYPE_DIRECT)
5618 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5619
5620 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5621 {
5622 IntUpdateBoundsRect(dc, &DestRect);
5623 }
5624 IntEngBitBlt(
5625 &psurf->SurfObj,
5626 NULL,
5627 NULL,
5628 (CLIPOBJ *)&dc->co,
5629 NULL,
5630 &DestRect,
5631 &SourcePoint,
5632 &SourcePoint,
5633 &dc->eboBackground.BrushObject,
5634 &BrushOrigin,
5635 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5636
5637 if (dc->dctype == DCTYPE_DIRECT)
5638 MouseSafetyOnDrawEnd(dc->ppdev);
5639
5640 BackgroundLeft = DestRect.right;
5641 }
5642
5643 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5644 DestRect.right = DestRect.left + realglyph->bitmap.width;
5645 DestRect.top = TextTop + yoff - realglyph->top;
5646 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5647
5648 bitSize.cx = realglyph->bitmap.width;
5649 bitSize.cy = realglyph->bitmap.rows;
5650 MaskRect.right = realglyph->bitmap.width;
5651 MaskRect.bottom = realglyph->bitmap.rows;
5652
5653 /* Check if the bitmap has any pixels */
5654 if ((bitSize.cx != 0) && (bitSize.cy != 0))
5655 {
5656 /*
5657 * We should create the bitmap out of the loop at the biggest possible
5658 * glyph size. Then use memset with 0 to clear it and sourcerect to
5659 * limit the work of the transbitblt.
5660 */
5661 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
5662 BMF_8BPP, BMF_TOPDOWN,
5663 realglyph->bitmap.buffer);
5664 if ( !HSourceGlyph )
5665 {
5666 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
5667 // FT_Done_Glyph(realglyph);
5668 bResult = FALSE;
5669 break;
5670 }
5671 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
5672 if ( !SourceGlyphSurf )
5673 {
5674 EngDeleteSurface((HSURF)HSourceGlyph);
5675 DPRINT1("WARNING: EngLockSurface() failed!\n");
5676 bResult = FALSE;
5677 break;
5678 }
5679
5680 /*
5681 * Use the font data as a mask to paint onto the DCs surface using a
5682 * brush.
5683 */
5684 if (lprc && (fuOptions & ETO_CLIPPED) &&
5685 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
5686 {
5687 // We do the check '>=' instead of '>' to possibly save an iteration
5688 // through this loop, since it's breaking after the drawing is done,
5689 // and x is always incremented.
5690 DestRect.right = lprc->right + dc->ptlDCOrig.x;
5691 DoBreak = TRUE;
5692 }
5693 if (lprc && (fuOptions & ETO_CLIPPED) &&
5694 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
5695 {
5696 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
5697 }
5698
5699 if (dc->dctype == DCTYPE_DIRECT)
5700 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5701
5702 if (!IntEngMaskBlt(
5703 SurfObj,
5704 SourceGlyphSurf,
5705 (CLIPOBJ *)&dc->co,
5706 &exloRGB2Dst.xlo,
5707 &exloDst2RGB.xlo,
5708 &DestRect,
5709 (PPOINTL)&MaskRect,
5710 &dc->eboText.BrushObject,
5711 &BrushOrigin))
5712 {
5713 DPRINT1("Failed to MaskBlt a glyph!\n");
5714 }
5715
5716 if (dc->dctype == DCTYPE_DIRECT)
5717 MouseSafetyOnDrawEnd(dc->ppdev) ;
5718
5719 EngUnlockSurface(SourceGlyphSurf);
5720 EngDeleteSurface((HSURF)HSourceGlyph);
5721 }
5722
5723 if (DoBreak)
5724 {
5725 break;
5726 }
5727
5728 if (plf->lfUnderline)
5729 {
5730 int i, position;
5731 if (!face->units_per_EM)
5732 {
5733 position = 0;
5734 }
5735 else
5736 {
5737 position = face->underline_position *
5738 face->size->metrics.y_ppem / face->units_per_EM;
5739 }
5740 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5741 {
5742 EngLineTo(SurfObj,
5743 (CLIPOBJ *)&dc->co,
5744 &dc->eboText.BrushObject,
5745 (TextLeft >> 6),
5746 TextTop + yoff - position + i,
5747 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5748 TextTop + yoff - position + i,
5749 NULL,
5750 ROP2_TO_MIX(R2_COPYPEN));
5751 }
5752 }
5753 if (plf->lfStrikeOut)
5754 {
5755 int i;
5756 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5757 {
5758 EngLineTo(SurfObj,
5759 (CLIPOBJ *)&dc->co,
5760 &dc->eboText.BrushObject,
5761 (TextLeft >> 6),
5762 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5763 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5764 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5765 NULL,
5766 ROP2_TO_MIX(R2_COPYPEN));
5767 }
5768 }
5769
5770 if (NULL == Dx)
5771 {
5772 TextLeft += realglyph->root.advance.x >> 10;
5773 DPRINT("New TextLeft: %I64d\n", TextLeft);
5774 }
5775 else
5776 {
5777 // FIXME this should probably be a matrix transform with TextTop as well.
5778 Scale = pdcattr->mxWorldToDevice.efM11;
5779 if (FLOATOBJ_Equal0(&Scale))
5780 FLOATOBJ_Set1(&Scale);
5781
5782 /* do the shift before multiplying to preserve precision */
5783 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5784 TextLeft += FLOATOBJ_GetLong(&Scale);
5785 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5786 }
5787
5788 if (DxShift)
5789 {
5790 TextTop -= Dx[2 * i + 1] << 6;
5791 }
5792
5793 previous = glyph_index;
5794
5795 if (EmuBold || EmuItalic)
5796 {
5797 FT_Done_Glyph((FT_Glyph)realglyph);
5798 realglyph = NULL;
5799 }
5800 }
5801
5802 if (pdcattr->lTextAlign & TA_UPDATECP) {
5803 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
5804 }
5805
5806 IntUnLockFreeType();
5807
5808 EXLATEOBJ_vCleanup(&exloRGB2Dst);
5809 EXLATEOBJ_vCleanup(&exloDst2RGB);
5810
5811 Cleanup:
5812
5813 DC_vFinishBlit(dc, NULL);
5814
5815 if (TextObj != NULL)
5816 TEXTOBJ_UnlockText(TextObj);
5817
5818 DC_UnlockDc(dc);
5819
5820 return bResult;
5821 }
5822
5823 #define STACK_TEXT_BUFFER_SIZE 100
5824 BOOL
5825 APIENTRY
5826 NtGdiExtTextOutW(
5827 IN HDC hDC,
5828 IN INT XStart,
5829 IN INT YStart,
5830 IN UINT fuOptions,
5831 IN OPTIONAL LPRECT UnsafeRect,
5832 IN LPWSTR UnsafeString,
5833 IN INT Count,
5834 IN OPTIONAL LPINT UnsafeDx,
5835 IN DWORD dwCodePage)
5836 {
5837 BOOL Result = FALSE;
5838 NTSTATUS Status = STATUS_SUCCESS;
5839 RECTL SafeRect;
5840 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
5841 PVOID Buffer = LocalBuffer;
5842 LPCWSTR SafeString = NULL;
5843 LPINT SafeDx = NULL;
5844 ULONG BufSize, StringSize, DxSize = 0;
5845
5846 /* Check if String is valid */
5847 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
5848 {
5849 EngSetLastError(ERROR_INVALID_PARAMETER);
5850 return FALSE;
5851 }
5852
5853 if (Count > 0)
5854 {
5855 /* Calculate buffer size for string and Dx values */
5856 BufSize = StringSize = Count * sizeof(WCHAR);
5857 if (UnsafeDx)
5858 {
5859 /* If ETO_PDY is specified, we have pairs of INTs */
5860 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
5861 BufSize += DxSize;
5862 }
5863
5864 /* Check if our local buffer is large enough */
5865 if (BufSize > STACK_TEXT_BUFFER_SIZE)
5866 {
5867 /* It's not, allocate a temp buffer */
5868 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
5869 if (!Buffer)
5870 {
5871 return FALSE;
5872 }
5873 }
5874
5875 /* Probe and copy user mode data to the buffer */
5876 _SEH2_TRY
5877 {
5878 /* Put the Dx before the String to assure alignment of 4 */
5879 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
5880
5881 /* Probe and copy the string */
5882 ProbeForRead(UnsafeString, StringSize, 1);
5883 memcpy((PVOID)SafeString, UnsafeString, StringSize);
5884
5885 /* If we have Dx values... */
5886 if (UnsafeDx)
5887 {
5888 /* ... probe and copy them */
5889 SafeDx = Buffer;
5890 ProbeForRead(UnsafeDx, DxSize, 1);
5891 memcpy(SafeDx, UnsafeDx, DxSize);
5892 }
5893 }
5894 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5895 {
5896 Status = _SEH2_GetExceptionCode();
5897 }
5898 _SEH2_END
5899 if (!NT_SUCCESS(Status))
5900 {
5901 goto cleanup;
5902 }
5903 }
5904
5905 /* If we have a rect, copy it */
5906 if (UnsafeRect)
5907 {
5908 _SEH2_TRY
5909 {
5910 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
5911 SafeRect = *UnsafeRect;
5912 }
5913 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5914 {
5915 Status = _SEH2_GetExceptionCode();
5916 }
5917 _SEH2_END
5918 if (!NT_SUCCESS(Status))
5919 {
5920 goto cleanup;
5921 }
5922 }
5923
5924 /* Finally call the internal routine */
5925 Result = GreExtTextOutW(hDC,
5926 XStart,
5927 YStart,
5928 fuOptions,
5929 &SafeRect,
5930 SafeString,
5931 Count,
5932 SafeDx,
5933 dwCodePage);
5934
5935 cleanup:
5936 /* If we allocated a buffer, free it */
5937 if (Buffer != LocalBuffer)
5938 {
5939 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
5940 }
5941
5942 return Result;
5943 }
5944
5945
5946 /*
5947 * @implemented
5948 */
5949 BOOL
5950 APIENTRY
5951 NtGdiGetCharABCWidthsW(
5952 IN HDC hDC,
5953 IN UINT FirstChar,
5954 IN ULONG Count,
5955 IN OPTIONAL PWCHAR UnSafepwch,
5956 IN FLONG fl,
5957 OUT PVOID Buffer)
5958 {
5959 LPABC SafeBuff;
5960 LPABCFLOAT SafeBuffF = NULL;
5961 PDC dc;
5962 PDC_ATTR pdcattr;
5963 PTEXTOBJ TextObj;
5964 PFONTGDI FontGDI;
5965 FT_Face face;
5966 FT_CharMap charmap, found = NULL;
5967 UINT i, glyph_index, BufferSize;
5968 HFONT hFont = 0;
5969 NTSTATUS Status = STATUS_SUCCESS;
5970 PMATRIX pmxWorldToDevice;
5971 PWCHAR Safepwch = NULL;
5972 LOGFONTW *plf;
5973
5974 if (!Buffer)
5975 {
5976 EngSetLastError(ERROR_INVALID_PARAMETER);
5977 return FALSE;
5978 }
5979
5980 if (UnSafepwch)
5981 {
5982 UINT pwchSize = Count * sizeof(WCHAR);
5983 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
5984
5985 if(!Safepwch)
5986 {
5987 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5988 return FALSE;
5989 }
5990
5991 _SEH2_TRY
5992 {
5993 ProbeForRead(UnSafepwch, pwchSize, 1);
5994 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
5995 }
5996 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5997 {
5998 Status = _SEH2_GetExceptionCode();
5999 }
6000 _SEH2_END;
6001 }
6002
6003 if (!NT_SUCCESS(Status))
6004 {
6005 if(Safepwch)
6006 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6007
6008 EngSetLastError(Status);
6009 return FALSE;
6010 }
6011
6012 BufferSize = Count * sizeof(ABC); // Same size!
6013 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6014 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
6015 if (SafeBuff == NULL)
6016 {
6017
6018 if(Safepwch)
6019 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6020
6021 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6022 return FALSE;
6023 }
6024
6025 dc = DC_LockDc(hDC);
6026 if (dc == NULL)
6027 {
6028 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6029
6030 if(Safepwch)
6031 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6032
6033 EngSetLastError(ERROR_INVALID_HANDLE);
6034 return FALSE;
6035 }
6036 pdcattr = dc->pdcattr;
6037 hFont = pdcattr->hlfntNew;
6038 TextObj = RealizeFontInit(hFont);
6039
6040 /* Get the DC's world-to-device transformation matrix */
6041 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6042 DC_UnlockDc(dc);
6043
6044 if (TextObj == NULL)
6045 {
6046 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6047
6048 if(Safepwch)
6049 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6050
6051 EngSetLastError(ERROR_INVALID_HANDLE);
6052 return FALSE;
6053 }
6054
6055 FontGDI = ObjToGDI(TextObj->Font, FONT);
6056
6057 face = FontGDI->SharedFace->Face;
6058 if (face->charmap == NULL)
6059 {
6060 for (i = 0; i < (UINT)face->num_charmaps; i++)
6061 {
6062 charmap = face->charmaps[i];
6063 if (charmap->encoding != 0)
6064 {
6065 found = charmap;
6066 break;
6067 }
6068 }
6069
6070 if (!found)
6071 {
6072 DPRINT1("WARNING: Could not find desired charmap!\n");
6073 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6074
6075 if(Safepwch)
6076 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6077
6078 EngSetLastError(ERROR_INVALID_HANDLE);
6079 return FALSE;
6080 }
6081
6082 IntLockFreeType();
6083 FT_Set_Charmap(face, found);
6084 IntUnLockFreeType();
6085 }
6086
6087 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6088 IntLockFreeType();
6089 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
6090 FtSetCoordinateTransform(face, pmxWorldToDevice);
6091
6092 for (i = FirstChar; i < FirstChar+Count; i++)
6093 {
6094 int adv, lsb, bbx, left, right;
6095
6096 if (Safepwch)
6097 {
6098 if (fl & GCABCW_INDICES)
6099 glyph_index = Safepwch[i - FirstChar];
6100 else
6101 glyph_index = FT_Get_Char_Index(face, Safepwch[i - FirstChar]);
6102 }
6103 else
6104 {
6105 if (fl & GCABCW_INDICES)
6106 glyph_index = i;
6107 else
6108 glyph_index = FT_Get_Char_Index(face, i);
6109 }
6110 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6111
6112 left = (INT)face->glyph->metrics.horiBearingX & -64;
6113 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
6114 adv = (face->glyph->advance.x + 32) >> 6;
6115
6116 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
6117 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
6118
6119 lsb = left >> 6;
6120 bbx = (right - left) >> 6;
6121 /*
6122 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
6123 */
6124 if (!fl)
6125 {
6126 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
6127 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
6128 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
6129 }
6130 else
6131 {
6132 SafeBuff[i - FirstChar].abcA = lsb;
6133 SafeBuff[i - FirstChar].abcB = bbx;
6134 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
6135 }
6136 }
6137 IntUnLockFreeType();
6138 TEXTOBJ_UnlockText(TextObj);
6139 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6140
6141 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6142
6143 if(Safepwch)
6144 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6145
6146 if (! NT_SUCCESS(Status))
6147 {
6148 SetLastNtError(Status);
6149 return FALSE;
6150 }
6151
6152 DPRINT("NtGdiGetCharABCWidths Worked!\n");
6153 return TRUE;
6154 }
6155
6156 /*
6157 * @implemented
6158 */
6159 BOOL
6160 APIENTRY
6161 NtGdiGetCharWidthW(
6162 IN HDC hDC,
6163 IN UINT FirstChar,
6164 IN UINT Count,
6165 IN OPTIONAL PWCHAR UnSafepwc,
6166 IN FLONG fl,
6167 OUT PVOID Buffer)
6168 {
6169 NTSTATUS Status = STATUS_SUCCESS;
6170 LPINT SafeBuff;
6171 PFLOAT SafeBuffF = NULL;
6172 PDC dc;
6173 PDC_ATTR pdcattr;
6174 PTEXTOBJ TextObj;
6175 PFONTGDI FontGDI;
6176 FT_Face face;
6177 FT_CharMap charmap, found = NULL;
6178 UINT i, glyph_index, BufferSize;
6179 HFONT hFont = 0;
6180 PMATRIX pmxWorldToDevice;
6181 PWCHAR Safepwc = NULL;
6182 LOGFONTW *plf;
6183
6184 if (UnSafepwc)
6185 {
6186 UINT pwcSize = Count * sizeof(WCHAR);
6187 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6188
6189 if(!Safepwc)
6190 {
6191 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6192 return FALSE;
6193 }
6194 _SEH2_TRY
6195 {
6196 ProbeForRead(UnSafepwc, pwcSize, 1);
6197 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6198 }
6199 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6200 {
6201 Status = _SEH2_GetExceptionCode();
6202 }
6203 _SEH2_END;
6204 }
6205
6206 if (!NT_SUCCESS(Status))
6207 {
6208 EngSetLastError(Status);
6209 return FALSE;
6210 }
6211
6212 BufferSize = Count * sizeof(INT); // Same size!
6213 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6214 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
6215 if (SafeBuff == NULL)
6216 {
6217 if(Safepwc)
6218 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6219
6220 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6221 return FALSE;
6222 }
6223
6224 dc = DC_LockDc(hDC);
6225 if (dc == NULL)
6226 {
6227 if(Safepwc)
6228 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6229
6230 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6231 EngSetLastError(ERROR_INVALID_HANDLE);
6232 return FALSE;
6233 }
6234 pdcattr = dc->pdcattr;
6235 hFont = pdcattr->hlfntNew;
6236 TextObj = RealizeFontInit(hFont);
6237 /* Get the DC's world-to-device transformation matrix */
6238 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6239 DC_UnlockDc(dc);
6240
6241 if (TextObj == NULL)
6242 {
6243 if(Safepwc)
6244 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6245
6246 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6247 EngSetLastError(ERROR_INVALID_HANDLE);
6248 return FALSE;
6249 }
6250
6251 FontGDI = ObjToGDI(TextObj->Font, FONT);
6252
6253 face = FontGDI->SharedFace->Face;
6254 if (face->charmap == NULL)
6255 {
6256 for (i = 0; i < (UINT)face->num_charmaps; i++)
6257 {
6258 charmap = face->charmaps[i];
6259 if (charmap->encoding != 0)
6260 {
6261 found = charmap;
6262 break;
6263 }
6264 }
6265
6266 if (!found)
6267 {
6268 DPRINT1("WARNING: Could not find desired charmap!\n");
6269
6270 if(Safepwc)
6271 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6272
6273 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6274 EngSetLastError(ERROR_INVALID_HANDLE);
6275 return FALSE;
6276 }
6277
6278 IntLockFreeType();
6279 FT_Set_Charmap(face, found);
6280 IntUnLockFreeType();
6281 }
6282
6283 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6284 IntLockFreeType();
6285 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
6286 FtSetCoordinateTransform(face, pmxWorldToDevice);
6287
6288 for (i = FirstChar; i < FirstChar+Count; i++)
6289 {
6290 if (Safepwc)
6291 {
6292 if (fl & GCW_INDICES)
6293 glyph_index = Safepwc[i - FirstChar];
6294 else
6295 glyph_index = FT_Get_Char_Index(face, Safepwc[i - FirstChar]);
6296 }
6297 else
6298 {
6299 if (fl & GCW_INDICES)
6300 glyph_index = i;
6301 else
6302 glyph_index = FT_Get_Char_Index(face, i);
6303 }
6304 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6305 if (!fl)
6306 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
6307 else
6308 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
6309 }
6310 IntUnLockFreeType();
6311 TEXTOBJ_UnlockText(TextObj);
6312 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6313
6314 if(Safepwc)
6315 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6316
6317 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6318 return TRUE;
6319 }
6320
6321
6322 /*
6323 * @implemented
6324 */
6325 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
6326 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
6327 // NOTE: See also GreGetGlyphIndicesW.
6328 __kernel_entry
6329 W32KAPI
6330 DWORD
6331 APIENTRY
6332 NtGdiGetGlyphIndicesW(
6333 _In_ HDC hdc,
6334 _In_reads_opt_(cwc) LPCWSTR pwc,
6335 _In_ INT cwc,
6336 _Out_writes_opt_(cwc) LPWORD pgi,
6337 _In_ DWORD iMode)
6338 {
6339 PDC dc;
6340 PDC_ATTR pdcattr;
6341 PTEXTOBJ TextObj;
6342 PFONTGDI FontGDI;
6343 HFONT hFont = NULL;
6344 NTSTATUS Status = STATUS_SUCCESS;
6345 OUTLINETEXTMETRICW *potm;
6346 INT i;
6347 WCHAR DefChar = 0xffff;
6348 PWSTR Buffer = NULL;
6349 ULONG Size, pwcSize;
6350 PWSTR Safepwc = NULL;
6351 LPCWSTR UnSafepwc = pwc;
6352 LPWORD UnSafepgi = pgi;
6353
6354 /* Check for integer overflow */
6355 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN
6356 return GDI_ERROR;
6357
6358 if (!UnSafepwc && !UnSafepgi)
6359 return cwc;
6360
6361 if (!UnSafepwc || !UnSafepgi)
6362 {
6363 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
6364 return GDI_ERROR;
6365 }
6366
6367 // TODO: Special undocumented case!
6368 if (!pwc && !pgi && (cwc == 0))
6369 {
6370 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n");
6371 return 0;
6372 }
6373
6374 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825
6375 if (cwc == 0)
6376 {
6377 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n");
6378 return GDI_ERROR;
6379 }
6380
6381 dc = DC_LockDc(hdc);
6382 if (!dc)
6383 {
6384 return GDI_ERROR;
6385 }
6386 pdcattr = dc->pdcattr;
6387 hFont = pdcattr->hlfntNew;
6388 TextObj = RealizeFontInit(hFont);
6389 DC_UnlockDc(dc);
6390 if (!TextObj)
6391 {
6392 return GDI_ERROR;
6393 }
6394
6395 FontGDI = ObjToGDI(TextObj->Font, FONT);
6396 TEXTOBJ_UnlockText(TextObj);
6397
6398 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
6399 if (!Buffer)
6400 {
6401 return GDI_ERROR;
6402 }
6403
6404 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
6405 {
6406 DefChar = 0xffff;
6407 }
6408 else
6409 {
6410 FT_Face Face = FontGDI->SharedFace->Face;
6411 if (FT_IS_SFNT(Face))
6412 {
6413 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
6414 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(Face, pOS2->usDefaultChar) : 0);
6415 }
6416 else
6417 {
6418 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
6419 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
6420 if (!potm)
6421 {
6422 cwc = GDI_ERROR;
6423 goto ErrorRet;
6424 }
6425 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
6426 if (Size)
6427 DefChar = potm->otmTextMetrics.tmDefaultChar;
6428 ExFreePoolWithTag(potm, GDITAG_TEXT);
6429 }
6430 }
6431
6432 pwcSize = cwc * sizeof(WCHAR);
6433 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6434
6435 if (!Safepwc)
6436 {
6437 Status = STATUS_NO_MEMORY;
6438 goto ErrorRet;
6439 }
6440
6441 _SEH2_TRY
6442 {
6443 ProbeForRead(UnSafepwc, pwcSize, 1);
6444 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6445 }
6446 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6447 {
6448 Status = _SEH2_GetExceptionCode();
6449 }
6450 _SEH2_END;
6451
6452 if (!NT_SUCCESS(Status)) goto ErrorRet;
6453
6454 IntLockFreeType();
6455
6456 for (i = 0; i < cwc; i++)
6457 {
6458 Buffer[i] = FT_Get_Char_Index(FontGDI->SharedFace->Face, Safepwc[i]);
6459 if (Buffer[i] == 0)
6460 {
6461 Buffer[i] = DefChar;
6462 }
6463 }
6464
6465 IntUnLockFreeType();
6466
6467 _SEH2_TRY
6468 {
6469 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
6470 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
6471 }
6472 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6473 {
6474 Status = _SEH2_GetExceptionCode();
6475 }
6476 _SEH2_END;
6477
6478 ErrorRet:
6479 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6480 if (Safepwc != NULL)
6481 {
6482 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6483 }
6484 if (NT_SUCCESS(Status)) return cwc;
6485 return GDI_ERROR;
6486 }
6487
6488 /* EOF */