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