[WIN32K] Remove old comments
[reactos.git] / reactos / 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 static const WORD gusEnglishUS = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
52
53 /* special font names */
54 static const UNICODE_STRING MarlettW = RTL_CONSTANT_STRING(L"Marlett");
55
56 /* registry */
57 static UNICODE_STRING FontRegPath =
58 RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
59
60
61 /* The FreeType library is not thread safe, so we have
62 to serialize access to it */
63 static PFAST_MUTEX FreeTypeLock;
64
65 static LIST_ENTRY FontListHead;
66 static PFAST_MUTEX FontListLock;
67 static BOOL RenderingEnabled = TRUE;
68
69 #define IntLockGlobalFonts \
70 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FontListLock)
71
72 #define IntUnLockGlobalFonts \
73 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
74
75 #define ASSERT_GLOBALFONTS_LOCK_HELD() \
76 ASSERT(FontListLock->Owner == KeGetCurrentThread())
77
78 #define IntLockFreeType \
79 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
80
81 #define IntUnLockFreeType \
82 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock)
83
84 #define ASSERT_FREETYPE_LOCK_HELD() \
85 ASSERT(FreeTypeLock->Owner == KeGetCurrentThread())
86
87 #define ASSERT_FREETYPE_LOCK_NOT_HELD() \
88 ASSERT(FreeTypeLock->Owner != KeGetCurrentThread())
89
90 #define MAX_FONT_CACHE 256
91
92 static LIST_ENTRY FontCacheListHead;
93 static UINT FontCacheNumEntries;
94
95 static PWCHAR ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */
96 {
97 L"Western", /* 00 */
98 L"Central_European",
99 L"Cyrillic",
100 L"Greek",
101 L"Turkish",
102 L"Hebrew",
103 L"Arabic",
104 L"Baltic",
105 L"Vietnamese", /* 08 */
106 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */
107 L"Thai",
108 L"Japanese",
109 L"CHINESE_GB2312",
110 L"Hangul",
111 L"CHINESE_BIG5",
112 L"Hangul(Johab)",
113 NULL, NULL, /* 23 */
114 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
115 L"Symbol" /* 31 */
116 };
117
118 /*
119 * For TranslateCharsetInfo
120 */
121 #define CP_SYMBOL 42
122 #define MAXTCIINDEX 32
123 static const CHARSETINFO FontTci[MAXTCIINDEX] =
124 {
125 /* ANSI */
126 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
127 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
128 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
129 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
130 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
131 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
132 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
133 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
134 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
135 /* reserved by ANSI */
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 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
143 /* ANSI and OEM */
144 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
145 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
146 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
147 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
148 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
149 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
150 /* Reserved for alternate ANSI and OEM */
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 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
159 /* Reserved for system */
160 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
161 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
162 };
163
164 /* list head */
165 static RTL_STATIC_LIST_HEAD(FontSubstListHead);
166
167 static void
168 SharedMem_AddRef(PSHARED_MEM Ptr)
169 {
170 ASSERT_FREETYPE_LOCK_HELD();
171
172 ++Ptr->RefCount;
173 }
174
175 static void
176 SharedFaceCache_Init(PSHARED_FACE_CACHE Cache)
177 {
178 Cache->OutlineRequiredSize = 0;
179 RtlInitUnicodeString(&Cache->FontFamily, NULL);
180 RtlInitUnicodeString(&Cache->FullName, NULL);
181 }
182
183 static PSHARED_FACE
184 SharedFace_Create(FT_Face Face, PSHARED_MEM Memory)
185 {
186 PSHARED_FACE Ptr;
187 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
188 if (Ptr)
189 {
190 Ptr->Face = Face;
191 Ptr->RefCount = 1;
192 Ptr->Memory = Memory;
193 SharedFaceCache_Init(&Ptr->EnglishUS);
194 SharedFaceCache_Init(&Ptr->UserLanguage);
195
196 SharedMem_AddRef(Memory);
197 DPRINT("Creating SharedFace for %s\n", Face->family_name);
198 }
199 return Ptr;
200 }
201
202 static PSHARED_MEM
203 SharedMem_Create(PBYTE Buffer, ULONG BufferSize, BOOL IsMapping)
204 {
205 PSHARED_MEM Ptr;
206 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_MEM), TAG_FONT);
207 if (Ptr)
208 {
209 Ptr->Buffer = Buffer;
210 Ptr->BufferSize = BufferSize;
211 Ptr->RefCount = 1;
212 Ptr->IsMapping = IsMapping;
213 DPRINT("Creating SharedMem for %p (%i, %p)\n", Buffer, IsMapping, Ptr);
214 }
215 return Ptr;
216 }
217
218 static void
219 SharedFace_AddRef(PSHARED_FACE Ptr)
220 {
221 ASSERT_FREETYPE_LOCK_HELD();
222
223 ++Ptr->RefCount;
224 }
225
226 static void
227 RemoveCachedEntry(PFONT_CACHE_ENTRY Entry)
228 {
229 ASSERT_FREETYPE_LOCK_HELD();
230
231 FT_Done_Glyph((FT_Glyph)Entry->BitmapGlyph);
232 RemoveEntryList(&Entry->ListEntry);
233 ExFreePoolWithTag(Entry, TAG_FONT);
234 FontCacheNumEntries--;
235 ASSERT(FontCacheNumEntries <= MAX_FONT_CACHE);
236 }
237
238 static void
239 RemoveCacheEntries(FT_Face Face)
240 {
241 PLIST_ENTRY CurrentEntry;
242 PFONT_CACHE_ENTRY FontEntry;
243
244 ASSERT_FREETYPE_LOCK_HELD();
245
246 CurrentEntry = FontCacheListHead.Flink;
247 while (CurrentEntry != &FontCacheListHead)
248 {
249 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
250 CurrentEntry = CurrentEntry->Flink;
251
252 if (FontEntry->Face == Face)
253 {
254 RemoveCachedEntry(FontEntry);
255 }
256 }
257 }
258
259 static void SharedMem_Release(PSHARED_MEM Ptr)
260 {
261 ASSERT_FREETYPE_LOCK_HELD();
262 ASSERT(Ptr->RefCount > 0);
263
264 if (Ptr->RefCount <= 0)
265 return;
266
267 --Ptr->RefCount;
268 if (Ptr->RefCount == 0)
269 {
270 DPRINT("Releasing SharedMem for %p (%i, %p)\n", Ptr->Buffer, Ptr->IsMapping, Ptr);
271 if (Ptr->IsMapping)
272 MmUnmapViewInSystemSpace(Ptr->Buffer);
273 else
274 ExFreePoolWithTag(Ptr->Buffer, TAG_FONT);
275 ExFreePoolWithTag(Ptr, TAG_FONT);
276 }
277 }
278
279 static void
280 SharedFaceCache_Release(PSHARED_FACE_CACHE Cache)
281 {
282 RtlFreeUnicodeString(&Cache->FontFamily);
283 RtlFreeUnicodeString(&Cache->FullName);
284 }
285
286 static void
287 SharedFace_Release(PSHARED_FACE Ptr)
288 {
289 IntLockFreeType;
290 ASSERT(Ptr->RefCount > 0);
291
292 if (Ptr->RefCount <= 0)
293 return;
294
295 --Ptr->RefCount;
296 if (Ptr->RefCount == 0)
297 {
298 DPRINT("Releasing SharedFace for %s\n", Ptr->Face->family_name);
299 RemoveCacheEntries(Ptr->Face);
300 FT_Done_Face(Ptr->Face);
301 SharedMem_Release(Ptr->Memory);
302 SharedFaceCache_Release(&Ptr->EnglishUS);
303 SharedFaceCache_Release(&Ptr->UserLanguage);
304 ExFreePoolWithTag(Ptr, TAG_FONT);
305 }
306 IntUnLockFreeType;
307 }
308
309
310 /*
311 * IntLoadFontSubstList --- loads the list of font substitutes
312 */
313 BOOL FASTCALL
314 IntLoadFontSubstList(PLIST_ENTRY pHead)
315 {
316 NTSTATUS Status;
317 HANDLE KeyHandle;
318 OBJECT_ATTRIBUTES ObjectAttributes;
319 KEY_FULL_INFORMATION KeyFullInfo;
320 ULONG i, Length;
321 UNICODE_STRING FromW, ToW;
322 BYTE InfoBuffer[128];
323 PKEY_VALUE_FULL_INFORMATION pInfo;
324 BYTE CharSets[FONTSUBST_FROM_AND_TO];
325 LPWSTR pch;
326 PFONTSUBST_ENTRY pEntry;
327
328 /* the FontSubstitutes registry key */
329 static UNICODE_STRING FontSubstKey =
330 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\"
331 L"Microsoft\\Windows NT\\CurrentVersion\\"
332 L"FontSubstitutes");
333
334 /* open registry key */
335 InitializeObjectAttributes(&ObjectAttributes, &FontSubstKey,
336 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
337 NULL, NULL);
338 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
339 if (!NT_SUCCESS(Status))
340 {
341 DPRINT("ZwOpenKey failed: 0x%08X\n", Status);
342 return FALSE; /* failure */
343 }
344
345 /* query count of values */
346 Status = ZwQueryKey(KeyHandle, KeyFullInformation,
347 &KeyFullInfo, sizeof(KeyFullInfo), &Length);
348 if (!NT_SUCCESS(Status))
349 {
350 DPRINT("ZwQueryKey failed: 0x%08X\n", Status);
351 ZwClose(KeyHandle);
352 return FALSE; /* failure */
353 }
354
355 /* for each value */
356 for (i = 0; i < KeyFullInfo.Values; ++i)
357 {
358 /* get value name */
359 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
360 InfoBuffer, sizeof(InfoBuffer), &Length);
361 if (!NT_SUCCESS(Status))
362 {
363 DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status);
364 break; /* failure */
365 }
366
367 /* create FromW string */
368 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
369 Length = pInfo->NameLength / sizeof(WCHAR);
370 pInfo->Name[Length] = UNICODE_NULL; /* truncate */
371 Status = RtlCreateUnicodeString(&FromW, pInfo->Name);
372 if (!NT_SUCCESS(Status))
373 {
374 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
375 break; /* failure */
376 }
377
378 /* query value */
379 Status = ZwQueryValueKey(KeyHandle, &FromW, KeyValueFullInformation,
380 InfoBuffer, sizeof(InfoBuffer), &Length);
381 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
382 if (!NT_SUCCESS(Status) || !pInfo->DataLength)
383 {
384 DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status);
385 RtlFreeUnicodeString(&FromW);
386 break; /* failure */
387 }
388
389 /* create ToW string */
390 pch = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
391 Length = pInfo->DataLength / sizeof(WCHAR);
392 pch[Length] = UNICODE_NULL; /* truncate */
393 Status = RtlCreateUnicodeString(&ToW, pch);
394 if (!NT_SUCCESS(Status))
395 {
396 DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
397 RtlFreeUnicodeString(&FromW);
398 break; /* failure */
399 }
400
401 /* does charset exist? (from) */
402 CharSets[FONTSUBST_FROM] = DEFAULT_CHARSET;
403 pch = wcsrchr(FromW.Buffer, L',');
404 if (pch)
405 {
406 /* truncate */
407 *pch = UNICODE_NULL;
408 FromW.Length = (pch - FromW.Buffer) * sizeof(WCHAR);
409 /* parse charset number */
410 CharSets[FONTSUBST_FROM] = (BYTE)_wtoi(pch + 1);
411 }
412
413 /* does charset exist? (to) */
414 CharSets[FONTSUBST_TO] = DEFAULT_CHARSET;
415 pch = wcsrchr(ToW.Buffer, L',');
416 if (pch)
417 {
418 /* truncate */
419 *pch = UNICODE_NULL;
420 ToW.Length = (pch - ToW.Buffer) * sizeof(WCHAR);
421 /* parse charset number */
422 CharSets[FONTSUBST_TO] = (BYTE)_wtoi(pch + 1);
423 }
424
425 /* allocate an entry */
426 pEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONTSUBST_ENTRY), TAG_FONT);
427 if (pEntry == NULL)
428 {
429 DPRINT("ExAllocatePoolWithTag failed\n");
430 RtlFreeUnicodeString(&FromW);
431 RtlFreeUnicodeString(&ToW);
432 break; /* failure */
433 }
434
435 /* store to *pEntry */
436 pEntry->FontNames[FONTSUBST_FROM] = FromW;
437 pEntry->FontNames[FONTSUBST_TO] = ToW;
438 pEntry->CharSets[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
439 pEntry->CharSets[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
440
441 /* insert pEntry to *pHead */
442 InsertTailList(pHead, &pEntry->ListEntry);
443 }
444
445 /* close now */
446 ZwClose(KeyHandle);
447
448 return NT_SUCCESS(Status);
449 }
450
451 BOOL FASTCALL
452 InitFontSupport(VOID)
453 {
454 ULONG ulError;
455
456 InitializeListHead(&FontListHead);
457 InitializeListHead(&FontCacheListHead);
458 FontCacheNumEntries = 0;
459 /* Fast Mutexes must be allocated from non paged pool */
460 FontListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
461 if (FontListLock == NULL)
462 {
463 return FALSE;
464 }
465
466 ExInitializeFastMutex(FontListLock);
467 FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
468 if (FreeTypeLock == NULL)
469 {
470 return FALSE;
471 }
472 ExInitializeFastMutex(FreeTypeLock);
473
474 ulError = FT_Init_FreeType(&library);
475 if (ulError)
476 {
477 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
478 return FALSE;
479 }
480
481 IntLoadSystemFonts();
482 IntLoadFontSubstList(&FontSubstListHead);
483
484 return TRUE;
485 }
486
487 VOID
488 FtSetCoordinateTransform(
489 FT_Face face,
490 PMATRIX pmx)
491 {
492 FT_Matrix ftmatrix;
493 FLOATOBJ efTemp;
494
495 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
496 efTemp = pmx->efM11;
497 FLOATOBJ_MulLong(&efTemp, 0x00010000);
498 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
499
500 efTemp = pmx->efM12;
501 FLOATOBJ_MulLong(&efTemp, 0x00010000);
502 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
503
504 efTemp = pmx->efM21;
505 FLOATOBJ_MulLong(&efTemp, 0x00010000);
506 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
507
508 efTemp = pmx->efM22;
509 FLOATOBJ_MulLong(&efTemp, 0x00010000);
510 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
511
512 /* Set the transformation matrix */
513 FT_Set_Transform(face, &ftmatrix, 0);
514 }
515
516 static BOOL
517 SubstituteFontByList(PLIST_ENTRY pHead,
518 PUNICODE_STRING pOutputName,
519 PUNICODE_STRING pInputName,
520 BYTE RequestedCharSet,
521 BYTE CharSetMap[FONTSUBST_FROM_AND_TO])
522 {
523 PLIST_ENTRY pListEntry;
524 PFONTSUBST_ENTRY pSubstEntry;
525 BYTE CharSets[FONTSUBST_FROM_AND_TO];
526
527 CharSetMap[FONTSUBST_FROM] = DEFAULT_CHARSET;
528 CharSetMap[FONTSUBST_TO] = RequestedCharSet;
529
530 /* for each list entry */
531 for (pListEntry = pHead->Flink;
532 pListEntry != pHead;
533 pListEntry = pListEntry->Flink)
534 {
535 pSubstEntry =
536 (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_ENTRY, ListEntry);
537
538 CharSets[FONTSUBST_FROM] = pSubstEntry->CharSets[FONTSUBST_FROM];
539
540 if (CharSets[FONTSUBST_FROM] != DEFAULT_CHARSET &&
541 CharSets[FONTSUBST_FROM] != RequestedCharSet)
542 {
543 continue; /* not matched */
544 }
545
546 /* does charset number exist? (to) */
547 if (pSubstEntry->CharSets[FONTSUBST_TO] != DEFAULT_CHARSET)
548 {
549 CharSets[FONTSUBST_TO] = pSubstEntry->CharSets[FONTSUBST_TO];
550 }
551 else
552 {
553 CharSets[FONTSUBST_TO] = RequestedCharSet;
554 }
555
556 /* does font name match? */
557 if (!RtlEqualUnicodeString(&pSubstEntry->FontNames[FONTSUBST_FROM],
558 pInputName, TRUE))
559 {
560 continue; /* not matched */
561 }
562
563 /* update *pOutputName */
564 *pOutputName = pSubstEntry->FontNames[FONTSUBST_TO];
565
566 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
567 {
568 /* update CharSetMap */
569 CharSetMap[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
570 CharSetMap[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
571 }
572 return TRUE; /* success */
573 }
574
575 return FALSE;
576 }
577
578 static BOOL
579 SubstituteFontRecurse(LOGFONTW* pLogFont)
580 {
581 UINT RecurseCount = 5;
582 UNICODE_STRING OutputNameW = { 0 };
583 BYTE CharSetMap[FONTSUBST_FROM_AND_TO];
584 BOOL Found;
585 UNICODE_STRING InputNameW;
586
587 if (pLogFont->lfFaceName[0] == UNICODE_NULL)
588 return FALSE;
589
590 RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
591
592 while (RecurseCount-- > 0)
593 {
594 Found = SubstituteFontByList(&FontSubstListHead,
595 &OutputNameW, &InputNameW,
596 pLogFont->lfCharSet, CharSetMap);
597 if (!Found)
598 break;
599
600 RtlStringCchCopyW(pLogFont->lfFaceName, LF_FACESIZE, OutputNameW.Buffer);
601
602 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
603 CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
604 {
605 pLogFont->lfCharSet = CharSetMap[FONTSUBST_TO];
606 }
607 }
608
609 return TRUE; /* success */
610 }
611
612 /*
613 * IntLoadSystemFonts
614 *
615 * Search the system font directory and adds each font found.
616 */
617 VOID FASTCALL
618 IntLoadSystemFonts(VOID)
619 {
620 OBJECT_ATTRIBUTES ObjectAttributes;
621 UNICODE_STRING Directory, FileName, TempString;
622 IO_STATUS_BLOCK Iosb;
623 HANDLE hDirectory;
624 BYTE *DirInfoBuffer;
625 PFILE_DIRECTORY_INFORMATION DirInfo;
626 BOOLEAN bRestartScan = TRUE;
627 NTSTATUS Status;
628 INT i;
629 static UNICODE_STRING SearchPatterns[] =
630 {
631 RTL_CONSTANT_STRING(L"*.ttf"),
632 RTL_CONSTANT_STRING(L"*.ttc"),
633 RTL_CONSTANT_STRING(L"*.otf"),
634 RTL_CONSTANT_STRING(L"*.otc"),
635 RTL_CONSTANT_STRING(L"*.fon"),
636 RTL_CONSTANT_STRING(L"*.fnt")
637 };
638
639 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
640
641 InitializeObjectAttributes(
642 &ObjectAttributes,
643 &Directory,
644 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
645 NULL,
646 NULL);
647
648 Status = ZwOpenFile(
649 &hDirectory,
650 SYNCHRONIZE | FILE_LIST_DIRECTORY,
651 &ObjectAttributes,
652 &Iosb,
653 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
654 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
655
656 if (NT_SUCCESS(Status))
657 {
658 for (i = 0; i < _countof(SearchPatterns); ++i)
659 {
660 DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
661 if (DirInfoBuffer == NULL)
662 {
663 ZwClose(hDirectory);
664 return;
665 }
666
667 FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
668 if (FileName.Buffer == NULL)
669 {
670 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
671 ZwClose(hDirectory);
672 return;
673 }
674 FileName.Length = 0;
675 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
676
677 while (1)
678 {
679 Status = ZwQueryDirectoryFile(
680 hDirectory,
681 NULL,
682 NULL,
683 NULL,
684 &Iosb,
685 DirInfoBuffer,
686 0x4000,
687 FileDirectoryInformation,
688 FALSE,
689 &SearchPatterns[i],
690 bRestartScan);
691
692 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
693 {
694 break;
695 }
696
697 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
698 while (1)
699 {
700 TempString.Buffer = DirInfo->FileName;
701 TempString.Length =
702 TempString.MaximumLength = DirInfo->FileNameLength;
703 RtlCopyUnicodeString(&FileName, &Directory);
704 RtlAppendUnicodeStringToString(&FileName, &TempString);
705 IntGdiAddFontResource(&FileName, 0);
706 if (DirInfo->NextEntryOffset == 0)
707 break;
708 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
709 }
710
711 bRestartScan = FALSE;
712 }
713
714 ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
715 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
716 }
717 ZwClose(hDirectory);
718 }
719 }
720
721 static BYTE
722 ItalicFromStyle(const char *style_name)
723 {
724 if (style_name == NULL || style_name[0] == 0)
725 return FALSE;
726 if (strstr(style_name, "Italic") != NULL)
727 return TRUE;
728 if (strstr(style_name, "Oblique") != NULL)
729 return TRUE;
730 return FALSE;
731 }
732
733 static LONG
734 WeightFromStyle(const char *style_name)
735 {
736 if (style_name == NULL || style_name[0] == 0)
737 return FW_NORMAL;
738 if (strstr(style_name, "Regular") != NULL)
739 return FW_REGULAR;
740 if (strstr(style_name, "Normal") != NULL)
741 return FW_NORMAL;
742 if (strstr(style_name, "SemiBold") != NULL)
743 return FW_SEMIBOLD;
744 if (strstr(style_name, "UltraBold") != NULL)
745 return FW_ULTRABOLD;
746 if (strstr(style_name, "DemiBold") != NULL)
747 return FW_DEMIBOLD;
748 if (strstr(style_name, "ExtraBold") != NULL)
749 return FW_EXTRABOLD;
750 if (strstr(style_name, "Bold") != NULL)
751 return FW_BOLD;
752 if (strstr(style_name, "UltraLight") != NULL)
753 return FW_ULTRALIGHT;
754 if (strstr(style_name, "ExtraLight") != NULL)
755 return FW_EXTRALIGHT;
756 if (strstr(style_name, "Light") != NULL)
757 return FW_LIGHT;
758 if (strstr(style_name, "Hairline") != NULL)
759 return 50;
760 if (strstr(style_name, "Book") != NULL)
761 return 350;
762 if (strstr(style_name, "ExtraBlack") != NULL)
763 return 950;
764 if (strstr(style_name, "UltraBlack") != NULL)
765 return 1000;
766 if (strstr(style_name, "Black") != NULL)
767 return FW_BLACK;
768 if (strstr(style_name, "Medium") != NULL)
769 return FW_MEDIUM;
770 if (strstr(style_name, "Thin") != NULL)
771 return FW_THIN;
772 if (strstr(style_name, "Heavy") != NULL)
773 return FW_HEAVY;
774 return FW_NORMAL;
775 }
776
777 static INT FASTCALL
778 IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
779 PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
780 {
781 FT_Error Error;
782 PFONT_ENTRY Entry;
783 FONT_ENTRY_MEM* PrivateEntry = NULL;
784 FONTGDI * FontGDI;
785 NTSTATUS Status;
786 FT_Face Face;
787 ANSI_STRING AnsiFaceName;
788 FT_WinFNT_HeaderRec WinFNT;
789 INT FaceCount = 0, CharSetCount = 0;
790 PUNICODE_STRING pFileName = pLoadFont->pFileName;
791 DWORD Characteristics = pLoadFont->Characteristics;
792 PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
793 TT_OS2 * pOS2;
794 INT BitIndex;
795 FT_UShort os2_version;
796 FT_ULong os2_ulCodePageRange1;
797 FT_UShort os2_usWeightClass;
798
799 if (SharedFace == NULL && CharSetIndex == -1)
800 {
801 /* load a face from memory */
802 IntLockFreeType;
803 Error = FT_New_Memory_Face(
804 library,
805 pLoadFont->Memory->Buffer,
806 pLoadFont->Memory->BufferSize,
807 ((FontIndex != -1) ? FontIndex : 0),
808 &Face);
809
810 if (!Error)
811 SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
812
813 IntUnLockFreeType;
814
815 if (!Error && FT_IS_SFNT(Face))
816 pLoadFont->IsTrueType = TRUE;
817
818 if (Error || SharedFace == NULL)
819 {
820 if (SharedFace)
821 SharedFace_Release(SharedFace);
822
823 if (Error == FT_Err_Unknown_File_Format)
824 DPRINT1("Unknown font file format\n");
825 else
826 DPRINT1("Error reading font (error code: %d)\n", Error);
827 return 0; /* failure */
828 }
829 }
830 else
831 {
832 Face = SharedFace->Face;
833 IntLockFreeType;
834 SharedFace_AddRef(SharedFace);
835 IntUnLockFreeType;
836 }
837
838 /* allocate a FONT_ENTRY */
839 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
840 if (!Entry)
841 {
842 SharedFace_Release(SharedFace);
843 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
844 return 0; /* failure */
845 }
846
847 /* allocate a FONTGDI */
848 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
849 if (!FontGDI)
850 {
851 SharedFace_Release(SharedFace);
852 ExFreePoolWithTag(Entry, TAG_FONT);
853 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
854 return 0; /* failure */
855 }
856
857 /* set file name */
858 if (pFileName)
859 {
860 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool,
861 pFileName->Length + sizeof(UNICODE_NULL),
862 GDITAG_PFF);
863 if (FontGDI->Filename == NULL)
864 {
865 EngFreeMem(FontGDI);
866 SharedFace_Release(SharedFace);
867 ExFreePoolWithTag(Entry, TAG_FONT);
868 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
869 return 0; /* failure */
870 }
871 RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
872 FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
873 }
874 else
875 {
876 FontGDI->Filename = NULL;
877
878 PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT);
879 if (!PrivateEntry)
880 {
881 if (FontGDI->Filename)
882 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
883 EngFreeMem(FontGDI);
884 SharedFace_Release(SharedFace);
885 ExFreePoolWithTag(Entry, TAG_FONT);
886 return 0;
887 }
888
889 PrivateEntry->Entry = Entry;
890 if (pLoadFont->PrivateEntry)
891 {
892 InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry);
893 }
894 else
895 {
896 InitializeListHead(&PrivateEntry->ListEntry);
897 pLoadFont->PrivateEntry = PrivateEntry;
898 }
899 }
900
901 /* set face */
902 FontGDI->SharedFace = SharedFace;
903 FontGDI->CharSet = ANSI_CHARSET;
904 FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name);
905 FontGDI->RequestItalic = FALSE;
906 FontGDI->OriginalWeight = WeightFromStyle(Face->style_name);
907 FontGDI->RequestWeight = FW_NORMAL;
908
909 RtlInitAnsiString(&AnsiFaceName, Face->family_name);
910 Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
911 if (!NT_SUCCESS(Status))
912 {
913 if (PrivateEntry)
914 {
915 if (pLoadFont->PrivateEntry == PrivateEntry)
916 {
917 pLoadFont->PrivateEntry = NULL;
918 }
919 else
920 {
921 RemoveEntryList(&PrivateEntry->ListEntry);
922 }
923 ExFreePoolWithTag(PrivateEntry, TAG_FONT);
924 }
925 if (FontGDI->Filename)
926 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
927 EngFreeMem(FontGDI);
928 SharedFace_Release(SharedFace);
929 ExFreePoolWithTag(Entry, TAG_FONT);
930 return 0;
931 }
932
933 os2_version = 0;
934 IntLockFreeType;
935 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
936 if (pOS2)
937 {
938 os2_version = pOS2->version;
939 os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
940 os2_usWeightClass = pOS2->usWeightClass;
941 }
942 IntUnLockFreeType;
943
944 if (pOS2 && os2_version >= 1)
945 {
946 /* get charset and weight from OS/2 header */
947
948 /* Make sure we do not use this pointer anymore */
949 pOS2 = NULL;
950
951 for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
952 {
953 if (os2_ulCodePageRange1 & (1 << BitIndex))
954 {
955 if (FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
956 continue;
957
958 if ((CharSetIndex == -1 && CharSetCount == 0) ||
959 CharSetIndex == CharSetCount)
960 {
961 FontGDI->CharSet = FontTci[BitIndex].ciCharset;
962 }
963
964 ++CharSetCount;
965 }
966 }
967
968 /* set actual weight */
969 FontGDI->OriginalWeight = os2_usWeightClass;
970 }
971 else
972 {
973 /* get charset from WinFNT header */
974 IntLockFreeType;
975 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
976 if (!Error)
977 {
978 FontGDI->CharSet = WinFNT.charset;
979 }
980 IntUnLockFreeType;
981 }
982
983 /* FIXME: CharSet is invalid on Marlett */
984 if (RtlEqualUnicodeString(&Entry->FaceName, &MarlettW, TRUE))
985 {
986 FontGDI->CharSet = SYMBOL_CHARSET;
987 }
988
989 ++FaceCount;
990 DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
991 DPRINT("Num glyphs: %d\n", Face->num_glyphs);
992 DPRINT("CharSet: %d\n", FontGDI->CharSet);
993
994 /* Add this font resource to the font table */
995 Entry->Font = FontGDI;
996 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
997
998 if (Characteristics & FR_PRIVATE)
999 {
1000 /* private font */
1001 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1002 IntLockProcessPrivateFonts(Win32Process);
1003 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
1004 IntUnLockProcessPrivateFonts(Win32Process);
1005 }
1006 else
1007 {
1008 /* global font */
1009 IntLockGlobalFonts;
1010 InsertTailList(&FontListHead, &Entry->ListEntry);
1011 IntUnLockGlobalFonts;
1012 }
1013
1014 if (FontIndex == -1)
1015 {
1016 if (FT_IS_SFNT(Face))
1017 {
1018 TT_Face TrueType = (TT_Face)Face;
1019 if (TrueType->ttc_header.count > 1)
1020 {
1021 FT_Long i;
1022 for (i = 1; i < TrueType->ttc_header.count; ++i)
1023 {
1024 FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
1025 }
1026 }
1027 }
1028 FontIndex = 0;
1029 }
1030
1031 if (CharSetIndex == -1)
1032 {
1033 INT i;
1034
1035 if (pLoadFont->RegValueName.Length == 0)
1036 {
1037 RtlCreateUnicodeString(pValueName, Entry->FaceName.Buffer);
1038 }
1039 else
1040 {
1041 UNICODE_STRING NewString;
1042 USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + Entry->FaceName.Length;
1043 NewString.Length = 0;
1044 NewString.MaximumLength = Length + sizeof(WCHAR);
1045 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1046 NewString.MaximumLength,
1047 TAG_USTR);
1048 NewString.Buffer[0] = UNICODE_NULL;
1049
1050 RtlAppendUnicodeStringToString(&NewString, pValueName);
1051 RtlAppendUnicodeToString(&NewString, L" & ");
1052 RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
1053
1054 RtlFreeUnicodeString(pValueName);
1055 *pValueName = NewString;
1056 }
1057
1058 for (i = 1; i < CharSetCount; ++i)
1059 {
1060 /* Do not count charsets towards 'faces' loaded */
1061 IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
1062 }
1063 }
1064
1065 return FaceCount; /* number of loaded faces */
1066 }
1067
1068 /*
1069 * IntGdiAddFontResource
1070 *
1071 * Adds the font resource from the specified file to the system.
1072 */
1073
1074 INT FASTCALL
1075 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
1076 {
1077 NTSTATUS Status;
1078 HANDLE FileHandle;
1079 PVOID Buffer = NULL;
1080 IO_STATUS_BLOCK Iosb;
1081 PVOID SectionObject;
1082 ULONG ViewSize = 0;
1083 LARGE_INTEGER SectionSize;
1084 OBJECT_ATTRIBUTES ObjectAttributes;
1085 GDI_LOAD_FONT LoadFont;
1086 INT FontCount;
1087 HANDLE KeyHandle;
1088 static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
1089
1090 /* Open the font file */
1091 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
1092 Status = ZwOpenFile(
1093 &FileHandle,
1094 FILE_GENERIC_READ | SYNCHRONIZE,
1095 &ObjectAttributes,
1096 &Iosb,
1097 FILE_SHARE_READ,
1098 FILE_SYNCHRONOUS_IO_NONALERT);
1099 if (!NT_SUCCESS(Status))
1100 {
1101 DPRINT("Could not load font file: %wZ\n", FileName);
1102 return 0;
1103 }
1104
1105 SectionSize.QuadPart = 0LL;
1106 Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
1107 NULL, &SectionSize, PAGE_READONLY,
1108 SEC_COMMIT, FileHandle, NULL);
1109 if (!NT_SUCCESS(Status))
1110 {
1111 DPRINT("Could not map file: %wZ\n", FileName);
1112 ZwClose(FileHandle);
1113 return 0;
1114 }
1115 ZwClose(FileHandle);
1116
1117 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
1118 if (!NT_SUCCESS(Status))
1119 {
1120 DPRINT("Could not map file: %wZ\n", FileName);
1121 ObDereferenceObject(SectionObject);
1122 return 0;
1123 }
1124
1125 LoadFont.pFileName = FileName;
1126 LoadFont.Memory = SharedMem_Create(Buffer, ViewSize, TRUE);
1127 LoadFont.Characteristics = Characteristics;
1128 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1129 LoadFont.IsTrueType = FALSE;
1130 LoadFont.PrivateEntry = NULL;
1131 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1132
1133 ObDereferenceObject(SectionObject);
1134
1135 /* Release our copy */
1136 IntLockFreeType;
1137 SharedMem_Release(LoadFont.Memory);
1138 IntUnLockFreeType;
1139
1140 if (FontCount > 0)
1141 {
1142 if (LoadFont.IsTrueType)
1143 {
1144 /* append " (TrueType)" */
1145 UNICODE_STRING NewString;
1146 USHORT Length;
1147
1148 Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length;
1149 NewString.Length = 0;
1150 NewString.MaximumLength = Length + sizeof(WCHAR);
1151 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
1152 NewString.MaximumLength,
1153 TAG_USTR);
1154 NewString.Buffer[0] = UNICODE_NULL;
1155
1156 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
1157 RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
1158 RtlFreeUnicodeString(&LoadFont.RegValueName);
1159 LoadFont.RegValueName = NewString;
1160 }
1161
1162 /* registry */
1163 InitializeObjectAttributes(&ObjectAttributes, &FontRegPath,
1164 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1165 NULL, NULL);
1166 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
1167 if (NT_SUCCESS(Status))
1168 {
1169 ULONG DataSize;
1170 LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
1171 if (pFileName)
1172 {
1173 pFileName++;
1174 DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
1175 ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
1176 pFileName, DataSize);
1177 }
1178 ZwClose(KeyHandle);
1179 }
1180 }
1181 RtlFreeUnicodeString(&LoadFont.RegValueName);
1182
1183 return FontCount;
1184 }
1185
1186 HANDLE FASTCALL
1187 IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
1188 {
1189 GDI_LOAD_FONT LoadFont;
1190 FONT_ENTRY_COLL_MEM* EntryCollection;
1191 INT FaceCount;
1192 HANDLE Ret = 0;
1193
1194 PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
1195
1196 if (!BufferCopy)
1197 {
1198 *pNumAdded = 0;
1199 return NULL;
1200 }
1201 memcpy(BufferCopy, Buffer, dwSize);
1202
1203 LoadFont.pFileName = NULL;
1204 LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
1205 LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
1206 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
1207 LoadFont.IsTrueType = FALSE;
1208 LoadFont.PrivateEntry = NULL;
1209 FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
1210
1211 RtlFreeUnicodeString(&LoadFont.RegValueName);
1212
1213 /* Release our copy */
1214 IntLockFreeType;
1215 SharedMem_Release(LoadFont.Memory);
1216 IntUnLockFreeType;
1217
1218 if (FaceCount > 0)
1219 {
1220 EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
1221 if (EntryCollection)
1222 {
1223 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1224 EntryCollection->Entry = LoadFont.PrivateEntry;
1225 IntLockProcessPrivateFonts(Win32Process);
1226 EntryCollection->Handle = ++Win32Process->PrivateMemFontHandleCount;
1227 InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
1228 IntUnLockProcessPrivateFonts(Win32Process);
1229 Ret = (HANDLE)EntryCollection->Handle;
1230 }
1231 }
1232 *pNumAdded = FaceCount;
1233
1234 return Ret;
1235 }
1236
1237 // FIXME: Add RemoveFontResource
1238
1239 static VOID FASTCALL
1240 CleanupFontEntry(PFONT_ENTRY FontEntry)
1241 {
1242 PFONTGDI FontGDI = FontEntry->Font;
1243 PSHARED_FACE SharedFace = FontGDI->SharedFace;
1244
1245 if (FontGDI->Filename)
1246 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1247
1248 EngFreeMem(FontGDI);
1249 SharedFace_Release(SharedFace);
1250 ExFreePoolWithTag(FontEntry, TAG_FONT);
1251 }
1252
1253 VOID FASTCALL
1254 IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
1255 {
1256 PLIST_ENTRY Entry;
1257 PFONT_ENTRY_MEM FontEntry;
1258
1259 while (!IsListEmpty(&Head->ListEntry))
1260 {
1261 Entry = RemoveHeadList(&Head->ListEntry);
1262 FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
1263
1264 CleanupFontEntry(FontEntry->Entry);
1265 ExFreePoolWithTag(FontEntry, TAG_FONT);
1266 }
1267
1268 CleanupFontEntry(Head->Entry);
1269 ExFreePoolWithTag(Head, TAG_FONT);
1270 }
1271
1272 static VOID FASTCALL
1273 UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)
1274 {
1275 PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
1276 PLIST_ENTRY ListEntry;
1277 RemoveEntryList(&Collection->ListEntry);
1278
1279 do {
1280 /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
1281 RemoveEntryList(&FontMemEntry->Entry->ListEntry);
1282
1283 ListEntry = FontMemEntry->ListEntry.Flink;
1284 FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
1285
1286 } while (FontMemEntry != Collection->Entry);
1287 }
1288
1289 BOOL FASTCALL
1290 IntGdiRemoveFontMemResource(HANDLE hMMFont)
1291 {
1292 PLIST_ENTRY Entry;
1293 PFONT_ENTRY_COLL_MEM CurrentEntry;
1294 PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
1295 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1296
1297 IntLockProcessPrivateFonts(Win32Process);
1298 Entry = Win32Process->PrivateMemFontListHead.Flink;
1299 while (Entry != &Win32Process->PrivateMemFontListHead)
1300 {
1301 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1302
1303 if (CurrentEntry->Handle == (UINT)hMMFont)
1304 {
1305 EntryCollection = CurrentEntry;
1306 UnlinkFontMemCollection(CurrentEntry);
1307 break;
1308 }
1309
1310 Entry = Entry->Flink;
1311 }
1312 IntUnLockProcessPrivateFonts(Win32Process);
1313
1314 if (EntryCollection)
1315 {
1316 IntGdiCleanupMemEntry(EntryCollection->Entry);
1317 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1318 return TRUE;
1319 }
1320 return FALSE;
1321 }
1322
1323
1324 VOID FASTCALL
1325 IntGdiCleanupPrivateFontsForProcess(VOID)
1326 {
1327 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1328 PLIST_ENTRY Entry;
1329 PFONT_ENTRY_COLL_MEM EntryCollection;
1330
1331 DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
1332 do {
1333 Entry = NULL;
1334 EntryCollection = NULL;
1335
1336 IntLockProcessPrivateFonts(Win32Process);
1337 if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
1338 {
1339 Entry = Win32Process->PrivateMemFontListHead.Flink;
1340 EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
1341 UnlinkFontMemCollection(EntryCollection);
1342 }
1343 IntUnLockProcessPrivateFonts(Win32Process);
1344
1345 if (EntryCollection)
1346 {
1347 IntGdiCleanupMemEntry(EntryCollection->Entry);
1348 ExFreePoolWithTag(EntryCollection, TAG_FONT);
1349 }
1350 else
1351 {
1352 /* No Mem fonts anymore, see if we have any other private fonts left */
1353 Entry = NULL;
1354 IntLockProcessPrivateFonts(Win32Process);
1355 if (!IsListEmpty(&Win32Process->PrivateFontListHead))
1356 {
1357 Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
1358 }
1359 IntUnLockProcessPrivateFonts(Win32Process);
1360
1361 if (Entry)
1362 {
1363 CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
1364 }
1365 }
1366
1367 } while (Entry);
1368 }
1369
1370 BOOL FASTCALL
1371 IntIsFontRenderingEnabled(VOID)
1372 {
1373 BOOL Ret = RenderingEnabled;
1374 HDC hDC;
1375
1376 hDC = IntGetScreenDC();
1377 if (hDC)
1378 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
1379
1380 return Ret;
1381 }
1382
1383 VOID FASTCALL
1384 IntEnableFontRendering(BOOL Enable)
1385 {
1386 RenderingEnabled = Enable;
1387 }
1388
1389 FT_Render_Mode FASTCALL
1390 IntGetFontRenderMode(LOGFONTW *logfont)
1391 {
1392 switch (logfont->lfQuality)
1393 {
1394 case ANTIALIASED_QUALITY:
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 PMATRIX pmx)
2612 {
2613 PLIST_ENTRY CurrentEntry;
2614 PFONT_CACHE_ENTRY FontEntry;
2615
2616 ASSERT_FREETYPE_LOCK_HELD();
2617
2618 CurrentEntry = FontCacheListHead.Flink;
2619 while (CurrentEntry != &FontCacheListHead)
2620 {
2621 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
2622 if ((FontEntry->Face == Face) &&
2623 (FontEntry->GlyphIndex == GlyphIndex) &&
2624 (FontEntry->Height == Height) &&
2625 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2626 break;
2627 CurrentEntry = CurrentEntry->Flink;
2628 }
2629
2630 if (CurrentEntry == &FontCacheListHead)
2631 {
2632 return NULL;
2633 }
2634
2635 RemoveEntryList(CurrentEntry);
2636 InsertHeadList(&FontCacheListHead, CurrentEntry);
2637 return FontEntry->BitmapGlyph;
2638 }
2639
2640 /* no cache */
2641 FT_BitmapGlyph APIENTRY
2642 ftGdiGlyphSet(
2643 FT_Face Face,
2644 FT_GlyphSlot GlyphSlot,
2645 FT_Render_Mode RenderMode)
2646 {
2647 FT_Glyph Glyph;
2648 INT error;
2649 FT_Bitmap AlignedBitmap;
2650 FT_BitmapGlyph BitmapGlyph;
2651
2652 error = FT_Get_Glyph(GlyphSlot, &Glyph);
2653 if (error)
2654 {
2655 DPRINT1("Failure getting glyph.\n");
2656 return NULL;
2657 }
2658
2659 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2660 if (error)
2661 {
2662 FT_Done_Glyph(Glyph);
2663 DPRINT1("Failure rendering glyph.\n");
2664 return NULL;
2665 }
2666
2667 BitmapGlyph = (FT_BitmapGlyph)Glyph;
2668 FT_Bitmap_New(&AlignedBitmap);
2669 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2670 {
2671 DPRINT1("Conversion failed\n");
2672 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2673 return NULL;
2674 }
2675
2676 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2677 BitmapGlyph->bitmap = AlignedBitmap;
2678
2679 return BitmapGlyph;
2680 }
2681
2682 FT_BitmapGlyph APIENTRY
2683 ftGdiGlyphCacheSet(
2684 FT_Face Face,
2685 INT GlyphIndex,
2686 INT Height,
2687 PMATRIX pmx,
2688 FT_GlyphSlot GlyphSlot,
2689 FT_Render_Mode RenderMode)
2690 {
2691 FT_Glyph GlyphCopy;
2692 INT error;
2693 PFONT_CACHE_ENTRY NewEntry;
2694 FT_Bitmap AlignedBitmap;
2695 FT_BitmapGlyph BitmapGlyph;
2696
2697 ASSERT_FREETYPE_LOCK_HELD();
2698
2699 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2700 if (error)
2701 {
2702 DPRINT1("Failure caching glyph.\n");
2703 return NULL;
2704 };
2705
2706 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2707 if (error)
2708 {
2709 FT_Done_Glyph(GlyphCopy);
2710 DPRINT1("Failure rendering glyph.\n");
2711 return NULL;
2712 };
2713
2714 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
2715 if (!NewEntry)
2716 {
2717 DPRINT1("Alloc failure caching glyph.\n");
2718 FT_Done_Glyph(GlyphCopy);
2719 return NULL;
2720 }
2721
2722 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2723 FT_Bitmap_New(&AlignedBitmap);
2724 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2725 {
2726 DPRINT1("Conversion failed\n");
2727 ExFreePoolWithTag(NewEntry, TAG_FONT);
2728 FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
2729 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2730 return NULL;
2731 }
2732
2733 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2734 BitmapGlyph->bitmap = AlignedBitmap;
2735
2736 NewEntry->GlyphIndex = GlyphIndex;
2737 NewEntry->Face = Face;
2738 NewEntry->BitmapGlyph = BitmapGlyph;
2739 NewEntry->Height = Height;
2740 NewEntry->mxWorldToDevice = *pmx;
2741
2742 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
2743 if (++FontCacheNumEntries > MAX_FONT_CACHE)
2744 {
2745 NewEntry = CONTAINING_RECORD(FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
2746 RemoveCachedEntry(NewEntry);
2747 }
2748
2749 return BitmapGlyph;
2750 }
2751
2752
2753 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2754 {
2755 pt->x.value = vec->x >> 6;
2756 pt->x.fract = (vec->x & 0x3f) << 10;
2757 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2758 pt->y.value = vec->y >> 6;
2759 pt->y.fract = (vec->y & 0x3f) << 10;
2760 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2761 }
2762
2763 /*
2764 This function builds an FT_Fixed from a float. It puts the integer part
2765 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2766 It fails if the integer part of the float number is greater than SHORT_MAX.
2767 */
2768 static __inline FT_Fixed FT_FixedFromFloat(float f)
2769 {
2770 short value = f;
2771 unsigned short fract = (f - value) * 0xFFFF;
2772 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2773 }
2774
2775 /*
2776 This function builds an FT_Fixed from a FIXED. It simply put f.value
2777 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2778 */
2779 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2780 {
2781 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2782 }
2783
2784 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2785 {
2786 TTPOLYGONHEADER *pph;
2787 TTPOLYCURVE *ppc;
2788 int needed = 0, point = 0, contour, first_pt;
2789 unsigned int pph_start, cpfx;
2790 DWORD type;
2791
2792 for (contour = 0; contour < outline->n_contours; contour++)
2793 {
2794 /* Ignore contours containing one point */
2795 if (point == outline->contours[contour])
2796 {
2797 point++;
2798 continue;
2799 }
2800
2801 pph_start = needed;
2802 pph = (TTPOLYGONHEADER *)(buf + needed);
2803 first_pt = point;
2804 if (buf)
2805 {
2806 pph->dwType = TT_POLYGON_TYPE;
2807 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2808 }
2809 needed += sizeof(*pph);
2810 point++;
2811 while (point <= outline->contours[contour])
2812 {
2813 ppc = (TTPOLYCURVE *)(buf + needed);
2814 type = outline->tags[point] & FT_Curve_Tag_On ?
2815 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2816 cpfx = 0;
2817 do
2818 {
2819 if (buf)
2820 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2821 cpfx++;
2822 point++;
2823 } while (point <= outline->contours[contour] &&
2824 (outline->tags[point] & FT_Curve_Tag_On) ==
2825 (outline->tags[point-1] & FT_Curve_Tag_On));
2826 /* At the end of a contour Windows adds the start point, but
2827 only for Beziers */
2828 if (point > outline->contours[contour] &&
2829 !(outline->tags[point-1] & FT_Curve_Tag_On))
2830 {
2831 if (buf)
2832 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2833 cpfx++;
2834 }
2835 else if (point <= outline->contours[contour] &&
2836 outline->tags[point] & FT_Curve_Tag_On)
2837 {
2838 /* add closing pt for bezier */
2839 if (buf)
2840 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2841 cpfx++;
2842 point++;
2843 }
2844 if (buf)
2845 {
2846 ppc->wType = type;
2847 ppc->cpfx = cpfx;
2848 }
2849 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2850 }
2851 if (buf)
2852 pph->cb = needed - pph_start;
2853 }
2854 return needed;
2855 }
2856
2857 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2858 {
2859 /* Convert the quadratic Beziers to cubic Beziers.
2860 The parametric eqn for a cubic Bezier is, from PLRM:
2861 r(t) = at^3 + bt^2 + ct + r0
2862 with the control points:
2863 r1 = r0 + c/3
2864 r2 = r1 + (c + b)/3
2865 r3 = r0 + c + b + a
2866
2867 A quadratic Bezier has the form:
2868 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2869
2870 So equating powers of t leads to:
2871 r1 = 2/3 p1 + 1/3 p0
2872 r2 = 2/3 p1 + 1/3 p2
2873 and of course r0 = p0, r3 = p2
2874 */
2875 int contour, point = 0, first_pt;
2876 TTPOLYGONHEADER *pph;
2877 TTPOLYCURVE *ppc;
2878 DWORD pph_start, cpfx, type;
2879 FT_Vector cubic_control[4];
2880 unsigned int needed = 0;
2881
2882 for (contour = 0; contour < outline->n_contours; contour++)
2883 {
2884 pph_start = needed;
2885 pph = (TTPOLYGONHEADER *)(buf + needed);
2886 first_pt = point;
2887 if (buf)
2888 {
2889 pph->dwType = TT_POLYGON_TYPE;
2890 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2891 }
2892 needed += sizeof(*pph);
2893 point++;
2894 while (point <= outline->contours[contour])
2895 {
2896 ppc = (TTPOLYCURVE *)(buf + needed);
2897 type = outline->tags[point] & FT_Curve_Tag_On ?
2898 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2899 cpfx = 0;
2900 do
2901 {
2902 if (type == TT_PRIM_LINE)
2903 {
2904 if (buf)
2905 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2906 cpfx++;
2907 point++;
2908 }
2909 else
2910 {
2911 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2912 so cpfx = 3n */
2913
2914 /* FIXME: Possible optimization in endpoint calculation
2915 if there are two consecutive curves */
2916 cubic_control[0] = outline->points[point-1];
2917 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2918 {
2919 cubic_control[0].x += outline->points[point].x + 1;
2920 cubic_control[0].y += outline->points[point].y + 1;
2921 cubic_control[0].x >>= 1;
2922 cubic_control[0].y >>= 1;
2923 }
2924 if (point+1 > outline->contours[contour])
2925 cubic_control[3] = outline->points[first_pt];
2926 else
2927 {
2928 cubic_control[3] = outline->points[point+1];
2929 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2930 {
2931 cubic_control[3].x += outline->points[point].x + 1;
2932 cubic_control[3].y += outline->points[point].y + 1;
2933 cubic_control[3].x >>= 1;
2934 cubic_control[3].y >>= 1;
2935 }
2936 }
2937 /* r1 = 1/3 p0 + 2/3 p1
2938 r2 = 1/3 p2 + 2/3 p1 */
2939 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2940 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2941 cubic_control[2] = cubic_control[1];
2942 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2943 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2944 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2945 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2946 if (buf)
2947 {
2948 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2949 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2950 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2951 }
2952 cpfx += 3;
2953 point++;
2954 }
2955 } while (point <= outline->contours[contour] &&
2956 (outline->tags[point] & FT_Curve_Tag_On) ==
2957 (outline->tags[point-1] & FT_Curve_Tag_On));
2958 /* At the end of a contour Windows adds the start point,
2959 but only for Beziers and we've already done that.
2960 */
2961 if (point <= outline->contours[contour] &&
2962 outline->tags[point] & FT_Curve_Tag_On)
2963 {
2964 /* This is the closing pt of a bezier, but we've already
2965 added it, so just inc point and carry on */
2966 point++;
2967 }
2968 if (buf)
2969 {
2970 ppc->wType = type;
2971 ppc->cpfx = cpfx;
2972 }
2973 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2974 }
2975 if (buf)
2976 pph->cb = needed - pph_start;
2977 }
2978 return needed;
2979 }
2980
2981 static INT
2982 IntRequestFontSize(PDC dc, FT_Face face, LONG Width, LONG Height)
2983 {
2984 FT_Size_RequestRec req;
2985
2986 if (Width < 0)
2987 Width = -Width;
2988
2989 if (Height < 0)
2990 {
2991 Height = -Height;
2992 }
2993 if (Height == 0)
2994 {
2995 Height = dc->ppdev->devinfo.lfDefaultFont.lfHeight;
2996 }
2997 if (Height == 0)
2998 {
2999 Height = Width;
3000 }
3001
3002 if (Height < 1)
3003 Height = 1;
3004
3005 if (Width > 0xFFFFU)
3006 Width = 0xFFFFU;
3007 if (Height > 0xFFFFU)
3008 Height = 0xFFFFU;
3009
3010 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
3011 req.width = (FT_Long)(Width << 6);
3012 req.height = (FT_Long)(Height << 6);
3013 req.horiResolution = 0;
3014 req.vertResolution = 0;
3015 return FT_Request_Size(face, &req);
3016 }
3017
3018 BOOL
3019 FASTCALL
3020 TextIntUpdateSize(PDC dc,
3021 PTEXTOBJ TextObj,
3022 PFONTGDI FontGDI,
3023 BOOL bDoLock)
3024 {
3025 FT_Face face;
3026 INT error, n;
3027 FT_CharMap charmap, found;
3028 LOGFONTW *plf;
3029
3030 if (bDoLock)
3031 IntLockFreeType;
3032
3033 face = FontGDI->SharedFace->Face;
3034 if (face->charmap == NULL)
3035 {
3036 DPRINT("WARNING: No charmap selected!\n");
3037 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3038
3039 found = NULL;
3040 for (n = 0; n < face->num_charmaps; n++)
3041 {
3042 charmap = face->charmaps[n];
3043 DPRINT("Found charmap encoding: %i\n", charmap->encoding);
3044 if (charmap->encoding != 0)
3045 {
3046 found = charmap;
3047 break;
3048 }
3049 }
3050 if (!found)
3051 {
3052 DPRINT1("WARNING: Could not find desired charmap!\n");
3053 }
3054 else
3055 {
3056 error = FT_Set_Charmap(face, found);
3057 if (error)
3058 {
3059 DPRINT1("WARNING: Could not set the charmap!\n");
3060 }
3061 }
3062 }
3063
3064 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3065
3066 error = IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
3067
3068 if (bDoLock)
3069 IntUnLockFreeType;
3070
3071 if (error)
3072 {
3073 DPRINT1("Error in setting pixel sizes: %d\n", error);
3074 return FALSE;
3075 }
3076
3077 return TRUE;
3078 }
3079
3080
3081 /*
3082 * Based on WineEngGetGlyphOutline
3083 *
3084 */
3085 ULONG
3086 FASTCALL
3087 ftGdiGetGlyphOutline(
3088 PDC dc,
3089 WCHAR wch,
3090 UINT iFormat,
3091 LPGLYPHMETRICS pgm,
3092 ULONG cjBuf,
3093 PVOID pvBuf,
3094 LPMAT2 pmat2,
3095 BOOL bIgnoreRotation)
3096 {
3097 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3098 PDC_ATTR pdcattr;
3099 PTEXTOBJ TextObj;
3100 PFONTGDI FontGDI;
3101 HFONT hFont = 0;
3102 GLYPHMETRICS gm;
3103 ULONG Size;
3104 FT_Face ft_face;
3105 FT_UInt glyph_index;
3106 DWORD width, height, pitch, needed = 0;
3107 FT_Bitmap ft_bitmap;
3108 FT_Error error;
3109 INT left, right, top = 0, bottom = 0;
3110 FT_Angle angle = 0;
3111 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3112 FLOAT eM11, widthRatio = 1.0;
3113 FT_Matrix transMat = identityMat;
3114 BOOL needsTransform = FALSE;
3115 INT orientation;
3116 LONG aveWidth;
3117 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3118 OUTLINETEXTMETRICW *potm;
3119 XFORM xForm;
3120 LOGFONTW *plf;
3121
3122 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3123 cjBuf, pvBuf, pmat2);
3124
3125 pdcattr = dc->pdcattr;
3126
3127 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
3128 eM11 = xForm.eM11;
3129
3130 hFont = pdcattr->hlfntNew;
3131 TextObj = RealizeFontInit(hFont);
3132
3133 if (!TextObj)
3134 {
3135 EngSetLastError(ERROR_INVALID_HANDLE);
3136 return GDI_ERROR;
3137 }
3138 FontGDI = ObjToGDI(TextObj->Font, FONT);
3139 ft_face = FontGDI->SharedFace->Face;
3140
3141 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3142 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3143 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3144
3145 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3146 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3147 if (!potm)
3148 {
3149 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3150 TEXTOBJ_UnlockText(TextObj);
3151 return GDI_ERROR;
3152 }
3153 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
3154 if (!Size)
3155 {
3156 /* FIXME: last error? */
3157 ExFreePoolWithTag(potm, GDITAG_TEXT);
3158 TEXTOBJ_UnlockText(TextObj);
3159 return GDI_ERROR;
3160 }
3161
3162 IntLockFreeType;
3163 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3164 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
3165
3166 TEXTOBJ_UnlockText(TextObj);
3167
3168 if (iFormat & GGO_GLYPH_INDEX)
3169 {
3170 glyph_index = wch;
3171 iFormat &= ~GGO_GLYPH_INDEX;
3172 }
3173 else glyph_index = FT_Get_Char_Index(ft_face, wch);
3174
3175 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3176 load_flags |= FT_LOAD_NO_BITMAP;
3177
3178 if (iFormat & GGO_UNHINTED)
3179 {
3180 load_flags |= FT_LOAD_NO_HINTING;
3181 iFormat &= ~GGO_UNHINTED;
3182 }
3183
3184 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3185 if (error)
3186 {
3187 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3188 IntUnLockFreeType;
3189 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3190 return GDI_ERROR;
3191 }
3192 IntUnLockFreeType;
3193
3194 if (aveWidth && potm)
3195 {
3196 widthRatio = (FLOAT)aveWidth * eM11 /
3197 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
3198 }
3199
3200 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3201 right = (INT)((ft_face->glyph->metrics.horiBearingX +
3202 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3203
3204 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3205 lsb = left >> 6;
3206 bbx = (right - left) >> 6;
3207
3208 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3209
3210 IntLockFreeType;
3211
3212 /* Scaling transform */
3213 /*if (aveWidth)*/
3214 {
3215
3216 FT_Matrix ftmatrix;
3217 FLOATOBJ efTemp;
3218
3219 PMATRIX pmx = DC_pmxWorldToDevice(dc);
3220
3221 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3222 efTemp = pmx->efM11;
3223 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3224 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
3225
3226 efTemp = pmx->efM12;
3227 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3228 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
3229
3230 efTemp = pmx->efM21;
3231 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3232 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
3233
3234 efTemp = pmx->efM22;
3235 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3236 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
3237
3238 FT_Matrix_Multiply(&ftmatrix, &transMat);
3239 needsTransform = TRUE;
3240 }
3241
3242 /* Rotation transform */
3243 if (orientation)
3244 {
3245 FT_Matrix rotationMat;
3246 FT_Vector vecAngle;
3247 DPRINT("Rotation Trans!\n");
3248 angle = FT_FixedFromFloat((float)orientation / 10.0);
3249 FT_Vector_Unit(&vecAngle, angle);
3250 rotationMat.xx = vecAngle.x;
3251 rotationMat.xy = -vecAngle.y;
3252 rotationMat.yx = -rotationMat.xy;
3253 rotationMat.yy = rotationMat.xx;
3254 FT_Matrix_Multiply(&rotationMat, &transMat);
3255 needsTransform = TRUE;
3256 }
3257
3258 /* Extra transformation specified by caller */
3259 if (pmat2)
3260 {
3261 FT_Matrix extraMat;
3262 DPRINT("MAT2 Matrix Trans!\n");
3263 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
3264 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
3265 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
3266 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
3267 FT_Matrix_Multiply(&extraMat, &transMat);
3268 needsTransform = TRUE;
3269 }
3270
3271 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
3272
3273 if (!needsTransform)
3274 {
3275 DPRINT("No Need to be Transformed!\n");
3276 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3277 bottom = (ft_face->glyph->metrics.horiBearingY -
3278 ft_face->glyph->metrics.height) & -64;
3279 gm.gmCellIncX = adv;
3280 gm.gmCellIncY = 0;
3281 }
3282 else
3283 {
3284 INT xc, yc;
3285 FT_Vector vec;
3286 for (xc = 0; xc < 2; xc++)
3287 {
3288 for (yc = 0; yc < 2; yc++)
3289 {
3290 vec.x = (ft_face->glyph->metrics.horiBearingX +
3291 xc * ft_face->glyph->metrics.width);
3292 vec.y = ft_face->glyph->metrics.horiBearingY -
3293 yc * ft_face->glyph->metrics.height;
3294 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
3295 FT_Vector_Transform(&vec, &transMat);
3296 if (xc == 0 && yc == 0)
3297 {
3298 left = right = vec.x;
3299 top = bottom = vec.y;
3300 }
3301 else
3302 {
3303 if (vec.x < left) left = vec.x;
3304 else if (vec.x > right) right = vec.x;
3305 if (vec.y < bottom) bottom = vec.y;
3306 else if (vec.y > top) top = vec.y;
3307 }
3308 }
3309 }
3310 left = left & -64;
3311 right = (right + 63) & -64;
3312 bottom = bottom & -64;
3313 top = (top + 63) & -64;
3314
3315 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3316 vec.x = ft_face->glyph->metrics.horiAdvance;
3317 vec.y = 0;
3318 FT_Vector_Transform(&vec, &transMat);
3319 gm.gmCellIncX = (vec.x+63) >> 6;
3320 gm.gmCellIncY = -((vec.y+63) >> 6);
3321 }
3322 gm.gmBlackBoxX = (right - left) >> 6;
3323 gm.gmBlackBoxY = (top - bottom) >> 6;
3324 gm.gmptGlyphOrigin.x = left >> 6;
3325 gm.gmptGlyphOrigin.y = top >> 6;
3326
3327 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
3328 gm.gmCellIncX, gm.gmCellIncY,
3329 gm.gmBlackBoxX, gm.gmBlackBoxY,
3330 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
3331
3332 IntUnLockFreeType;
3333
3334
3335 if (iFormat == GGO_METRICS)
3336 {
3337 DPRINT("GGO_METRICS Exit!\n");
3338 *pgm = gm;
3339 return 1; /* FIXME */
3340 }
3341
3342 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
3343 {
3344 DPRINT1("Loaded a bitmap\n");
3345 return GDI_ERROR;
3346 }
3347
3348 switch (iFormat)
3349 {
3350 case GGO_BITMAP:
3351 width = gm.gmBlackBoxX;
3352 height = gm.gmBlackBoxY;
3353 pitch = ((width + 31) >> 5) << 2;
3354 needed = pitch * height;
3355
3356 if (!pvBuf || !cjBuf) break;
3357 if (!needed) return GDI_ERROR; /* empty glyph */
3358 if (needed > cjBuf)
3359 return GDI_ERROR;
3360
3361 switch (ft_face->glyph->format)
3362 {
3363 case ft_glyph_format_bitmap:
3364 {
3365 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3366 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
3367 INT h = min( height, ft_face->glyph->bitmap.rows );
3368 while (h--)
3369 {
3370 RtlCopyMemory(dst, src, w);
3371 src += ft_face->glyph->bitmap.pitch;
3372 dst += pitch;
3373 }
3374 break;
3375 }
3376
3377 case ft_glyph_format_outline:
3378 ft_bitmap.width = width;
3379 ft_bitmap.rows = height;
3380 ft_bitmap.pitch = pitch;
3381 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
3382 ft_bitmap.buffer = pvBuf;
3383
3384 IntLockFreeType;
3385 if (needsTransform)
3386 {
3387 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3388 }
3389 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3390 /* Note: FreeType will only set 'black' bits for us. */
3391 RtlZeroMemory(pvBuf, needed);
3392 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3393 IntUnLockFreeType;
3394 break;
3395
3396 default:
3397 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3398 return GDI_ERROR;
3399 }
3400 break;
3401
3402 case GGO_GRAY2_BITMAP:
3403 case GGO_GRAY4_BITMAP:
3404 case GGO_GRAY8_BITMAP:
3405 {
3406 unsigned int mult, row, col;
3407 BYTE *start, *ptr;
3408
3409 width = gm.gmBlackBoxX;
3410 height = gm.gmBlackBoxY;
3411 pitch = (width + 3) / 4 * 4;
3412 needed = pitch * height;
3413
3414 if (!pvBuf || !cjBuf) break;
3415 if (!needed) return GDI_ERROR; /* empty glyph */
3416 if (needed > cjBuf)
3417 return GDI_ERROR;
3418
3419 switch (ft_face->glyph->format)
3420 {
3421 case ft_glyph_format_bitmap:
3422 {
3423 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3424 INT h = min( height, ft_face->glyph->bitmap.rows );
3425 INT x;
3426 while (h--)
3427 {
3428 for (x = 0; (UINT)x < pitch; x++)
3429 {
3430 if (x < ft_face->glyph->bitmap.width)
3431 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3432 else
3433 dst[x] = 0;
3434 }
3435 src += ft_face->glyph->bitmap.pitch;
3436 dst += pitch;
3437 }
3438 break;
3439 }
3440 case ft_glyph_format_outline:
3441 {
3442 ft_bitmap.width = width;
3443 ft_bitmap.rows = height;
3444 ft_bitmap.pitch = pitch;
3445 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3446 ft_bitmap.buffer = pvBuf;
3447
3448 IntLockFreeType;
3449 if (needsTransform)
3450 {
3451 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3452 }
3453 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3454 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
3455 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3456 IntUnLockFreeType;
3457
3458 if (iFormat == GGO_GRAY2_BITMAP)
3459 mult = 4;
3460 else if (iFormat == GGO_GRAY4_BITMAP)
3461 mult = 16;
3462 else if (iFormat == GGO_GRAY8_BITMAP)
3463 mult = 64;
3464 else
3465 {
3466 return GDI_ERROR;
3467 }
3468
3469 start = pvBuf;
3470 for (row = 0; row < height; row++)
3471 {
3472 ptr = start;
3473 for (col = 0; col < width; col++, ptr++)
3474 {
3475 *ptr = (((int)*ptr) * mult + 128) / 256;
3476 }
3477 start += pitch;
3478 }
3479
3480 break;
3481 }
3482 default:
3483 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3484 return GDI_ERROR;
3485 }
3486 }
3487
3488 case GGO_NATIVE:
3489 {
3490 FT_Outline *outline = &ft_face->glyph->outline;
3491
3492 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
3493
3494 IntLockFreeType;
3495 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
3496
3497 needed = get_native_glyph_outline(outline, cjBuf, NULL);
3498
3499 if (!pvBuf || !cjBuf)
3500 {
3501 IntUnLockFreeType;
3502 break;
3503 }
3504 if (needed > cjBuf)
3505 {
3506 IntUnLockFreeType;
3507 return GDI_ERROR;
3508 }
3509 get_native_glyph_outline(outline, cjBuf, pvBuf);
3510 IntUnLockFreeType;
3511 break;
3512 }
3513 case GGO_BEZIER:
3514 {
3515 FT_Outline *outline = &ft_face->glyph->outline;
3516 if (cjBuf == 0) pvBuf = NULL;
3517
3518 if (needsTransform && pvBuf)
3519 {
3520 IntLockFreeType;
3521 FT_Outline_Transform(outline, &transMat);
3522 IntUnLockFreeType;
3523 }
3524 needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
3525
3526 if (!pvBuf || !cjBuf)
3527 break;
3528 if (needed > cjBuf)
3529 return GDI_ERROR;
3530
3531 get_bezier_glyph_outline(outline, cjBuf, pvBuf);
3532 break;
3533 }
3534
3535 default:
3536 DPRINT1("Unsupported format %u\n", iFormat);
3537 return GDI_ERROR;
3538 }
3539
3540 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
3541 *pgm = gm;
3542 return needed;
3543 }
3544
3545 BOOL
3546 FASTCALL
3547 TextIntGetTextExtentPoint(PDC dc,
3548 PTEXTOBJ TextObj,
3549 LPCWSTR String,
3550 INT Count,
3551 ULONG MaxExtent,
3552 LPINT Fit,
3553 LPINT Dx,
3554 LPSIZE Size,
3555 FLONG fl)
3556 {
3557 PFONTGDI FontGDI;
3558 FT_Face face;
3559 FT_GlyphSlot glyph;
3560 FT_BitmapGlyph realglyph;
3561 INT error, glyph_index, i, previous;
3562 ULONGLONG TotalWidth = 0;
3563 BOOL use_kerning;
3564 FT_Render_Mode RenderMode;
3565 BOOLEAN Render;
3566 PMATRIX pmxWorldToDevice;
3567 LOGFONTW *plf;
3568 BOOL EmuBold, EmuItalic;
3569
3570 FontGDI = ObjToGDI(TextObj->Font, FONT);
3571
3572 face = FontGDI->SharedFace->Face;
3573 if (NULL != Fit)
3574 {
3575 *Fit = 0;
3576 }
3577
3578 IntLockFreeType;
3579
3580 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3581
3582 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3583 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
3584 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
3585
3586 Render = IntIsFontRenderingEnabled();
3587 if (Render)
3588 RenderMode = IntGetFontRenderMode(plf);
3589 else
3590 RenderMode = FT_RENDER_MODE_MONO;
3591
3592
3593 /* Get the DC's world-to-device transformation matrix */
3594 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3595 FtSetCoordinateTransform(face, pmxWorldToDevice);
3596
3597 use_kerning = FT_HAS_KERNING(face);
3598 previous = 0;
3599
3600 for (i = 0; i < Count; i++)
3601 {
3602 if (fl & GTEF_INDICES)
3603 glyph_index = *String;
3604 else
3605 glyph_index = FT_Get_Char_Index(face, *String);
3606
3607 if (EmuBold || EmuItalic)
3608 realglyph = NULL;
3609 else
3610 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3611 plf->lfHeight, pmxWorldToDevice);
3612
3613 if (EmuBold || EmuItalic || !realglyph)
3614 {
3615 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3616 if (error)
3617 {
3618 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
3619 break;
3620 }
3621
3622 glyph = face->glyph;
3623 if (EmuBold || EmuItalic)
3624 {
3625 if (EmuBold)
3626 FT_GlyphSlot_Embolden(glyph);
3627 if (EmuItalic)
3628 FT_GlyphSlot_Oblique(glyph);
3629 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
3630 }
3631 else
3632 {
3633 realglyph = ftGdiGlyphCacheSet(face,
3634 glyph_index,
3635 plf->lfHeight,
3636 pmxWorldToDevice,
3637 glyph,
3638 RenderMode);
3639 }
3640
3641 if (!realglyph)
3642 {
3643 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3644 break;
3645 }
3646 }
3647
3648 /* Retrieve kerning distance */
3649 if (use_kerning && previous && glyph_index)
3650 {
3651 FT_Vector delta;
3652 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3653 TotalWidth += delta.x;
3654 }
3655
3656 TotalWidth += realglyph->root.advance.x >> 10;
3657
3658 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
3659 {
3660 *Fit = i + 1;
3661 }
3662 if (NULL != Dx)
3663 {
3664 Dx[i] = (TotalWidth + 32) >> 6;
3665 }
3666
3667 if (EmuBold || EmuItalic)
3668 {
3669 FT_Done_Glyph((FT_Glyph)realglyph);
3670 realglyph = NULL;
3671 }
3672
3673 previous = glyph_index;
3674 String++;
3675 }
3676 IntUnLockFreeType;
3677
3678 Size->cx = (TotalWidth + 32) >> 6;
3679 Size->cy = (plf->lfHeight == 0 ?
3680 dc->ppdev->devinfo.lfDefaultFont.lfHeight :
3681 abs(plf->lfHeight));
3682 Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
3683
3684 return TRUE;
3685 }
3686
3687
3688 INT
3689 FASTCALL
3690 ftGdiGetTextCharsetInfo(
3691 PDC Dc,
3692 LPFONTSIGNATURE lpSig,
3693 DWORD dwFlags)
3694 {
3695 PDC_ATTR pdcattr;
3696 UINT Ret = DEFAULT_CHARSET;
3697 INT i;
3698 HFONT hFont;
3699 PTEXTOBJ TextObj;
3700 PFONTGDI FontGdi;
3701 FONTSIGNATURE fs;
3702 TT_OS2 *pOS2;
3703 FT_Face Face;
3704 CHARSETINFO csi;
3705 DWORD cp, fs0;
3706 USHORT usACP, usOEM;
3707
3708 pdcattr = Dc->pdcattr;
3709 hFont = pdcattr->hlfntNew;
3710 TextObj = RealizeFontInit(hFont);
3711
3712 if (!TextObj)
3713 {
3714 EngSetLastError(ERROR_INVALID_HANDLE);
3715 return Ret;
3716 }
3717 FontGdi = ObjToGDI(TextObj->Font, FONT);
3718 Face = FontGdi->SharedFace->Face;
3719 TEXTOBJ_UnlockText(TextObj);
3720
3721 IntLockFreeType;
3722 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3723 IntUnLockFreeType;
3724 memset(&fs, 0, sizeof(FONTSIGNATURE));
3725 if (NULL != pOS2)
3726 {
3727 fs.fsCsb[0] = pOS2->ulCodePageRange1;
3728 fs.fsCsb[1] = pOS2->ulCodePageRange2;
3729 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3730 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3731 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3732 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3733 if (pOS2->version == 0)
3734 {
3735 FT_UInt dummy;
3736
3737 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
3738 fs.fsCsb[0] |= FS_LATIN1;
3739 else
3740 fs.fsCsb[0] |= FS_SYMBOL;
3741 }
3742 }
3743 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
3744 if (fs.fsCsb[0] == 0)
3745 { /* Let's see if we can find any interesting cmaps */
3746 for (i = 0; i < Face->num_charmaps; i++)
3747 {
3748 switch (Face->charmaps[i]->encoding)
3749 {
3750 case FT_ENCODING_UNICODE:
3751 case FT_ENCODING_APPLE_ROMAN:
3752 fs.fsCsb[0] |= FS_LATIN1;
3753 break;
3754 case FT_ENCODING_MS_SYMBOL:
3755 fs.fsCsb[0] |= FS_SYMBOL;
3756 break;
3757 default:
3758 break;
3759 }
3760 }
3761 }
3762 if (lpSig)
3763 {
3764 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
3765 }
3766
3767 RtlGetDefaultCodePage(&usACP, &usOEM);
3768 cp = usACP;
3769
3770 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
3771 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
3772 {
3773 DPRINT("Hit 1\n");
3774 Ret = csi.ciCharset;
3775 goto Exit;
3776 }
3777
3778 for (i = 0; i < MAXTCIINDEX; i++)
3779 {
3780 fs0 = 1L << i;
3781 if (fs.fsCsb[0] & fs0)
3782 {
3783 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
3784 {
3785 // *cp = csi.ciACP;
3786 DPRINT("Hit 2\n");
3787 Ret = csi.ciCharset;
3788 goto Exit;
3789 }
3790 else
3791 DPRINT1("TCI failing on %x\n", fs0);
3792 }
3793 }
3794 Exit:
3795 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
3796 return (MAKELONG(csi.ciACP, csi.ciCharset));
3797 }
3798
3799
3800 DWORD
3801 FASTCALL
3802 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
3803 {
3804 DWORD size = 0;
3805 DWORD num_ranges = 0;
3806 FT_Face face = Font->SharedFace->Face;
3807
3808 if (face->charmap->encoding == FT_ENCODING_UNICODE)
3809 {
3810 FT_UInt glyph_code = 0;
3811 FT_ULong char_code, char_code_prev;
3812
3813 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
3814
3815 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3816 face->num_glyphs, glyph_code, char_code);
3817
3818 if (!glyph_code) return 0;
3819
3820 if (glyphset)
3821 {
3822 glyphset->ranges[0].wcLow = (USHORT)char_code;
3823 glyphset->ranges[0].cGlyphs = 0;
3824 glyphset->cGlyphsSupported = 0;
3825 }
3826
3827 num_ranges = 1;
3828 while (glyph_code)
3829 {
3830 if (char_code < char_code_prev)
3831 {
3832 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
3833 return 0;
3834 }
3835 if (char_code - char_code_prev > 1)
3836 {
3837 num_ranges++;
3838 if (glyphset)
3839 {
3840 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
3841 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
3842 glyphset->cGlyphsSupported++;
3843 }
3844 }
3845 else if (glyphset)
3846 {
3847 glyphset->ranges[num_ranges - 1].cGlyphs++;
3848 glyphset->cGlyphsSupported++;
3849 }
3850 char_code_prev = char_code;
3851 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
3852 }
3853 }
3854 else
3855 DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
3856
3857 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
3858 if (glyphset)
3859 {
3860 glyphset->cbThis = size;
3861 glyphset->cRanges = num_ranges;
3862 glyphset->flAccel = 0;
3863 }
3864 return size;
3865 }
3866
3867
3868 BOOL
3869 FASTCALL
3870 ftGdiGetTextMetricsW(
3871 HDC hDC,
3872 PTMW_INTERNAL ptmwi)
3873 {
3874 PDC dc;
3875 PDC_ATTR pdcattr;
3876 PTEXTOBJ TextObj;
3877 PFONTGDI FontGDI;
3878 FT_Face Face;
3879 TT_OS2 *pOS2;
3880 TT_HoriHeader *pHori;
3881 FT_WinFNT_HeaderRec Win;
3882 ULONG Error;
3883 NTSTATUS Status = STATUS_SUCCESS;
3884 LOGFONTW *plf;
3885
3886 if (!ptmwi)
3887 {
3888 EngSetLastError(STATUS_INVALID_PARAMETER);
3889 return FALSE;
3890 }
3891
3892 if (!(dc = DC_LockDc(hDC)))
3893 {
3894 EngSetLastError(ERROR_INVALID_HANDLE);
3895 return FALSE;
3896 }
3897 pdcattr = dc->pdcattr;
3898 TextObj = RealizeFontInit(pdcattr->hlfntNew);
3899 if (NULL != TextObj)
3900 {
3901 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3902 FontGDI = ObjToGDI(TextObj->Font, FONT);
3903
3904 Face = FontGDI->SharedFace->Face;
3905 IntLockFreeType;
3906 Error = IntRequestFontSize(dc, Face, plf->lfWidth, plf->lfHeight);
3907 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
3908 IntUnLockFreeType;
3909 if (0 != Error)
3910 {
3911 DPRINT1("Error in setting pixel sizes: %u\n", Error);
3912 Status = STATUS_UNSUCCESSFUL;
3913 }
3914 else
3915 {
3916 FT_Face Face = FontGDI->SharedFace->Face;
3917 Status = STATUS_SUCCESS;
3918
3919 IntLockFreeType;
3920 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3921 if (NULL == pOS2)
3922 {
3923 DPRINT1("Can't find OS/2 table - not TT font?\n");
3924 Status = STATUS_INTERNAL_ERROR;
3925 }
3926
3927 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
3928 if (NULL == pHori)
3929 {
3930 DPRINT1("Can't find HHEA table - not TT font?\n");
3931 Status = STATUS_INTERNAL_ERROR;
3932 }
3933
3934 Error = FT_Get_WinFNT_Header(Face, &Win);
3935
3936 IntUnLockFreeType;
3937
3938 if (NT_SUCCESS(Status))
3939 {
3940 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
3941
3942 /* FIXME: Fill Diff member */
3943 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
3944 }
3945 }
3946 TEXTOBJ_UnlockText(TextObj);
3947 }
3948 else
3949 {
3950 Status = STATUS_INVALID_HANDLE;
3951 }
3952 DC_UnlockDc(dc);
3953
3954 if (!NT_SUCCESS(Status))
3955 {
3956 SetLastNtError(Status);
3957 return FALSE;
3958 }
3959 return TRUE;
3960 }
3961
3962 DWORD
3963 FASTCALL
3964 ftGdiGetFontData(
3965 PFONTGDI FontGdi,
3966 DWORD Table,
3967 DWORD Offset,
3968 PVOID Buffer,
3969 DWORD Size)
3970 {
3971 DWORD Result = GDI_ERROR;
3972 FT_Face Face = FontGdi->SharedFace->Face;
3973
3974 IntLockFreeType;
3975
3976 if (FT_IS_SFNT(Face))
3977 {
3978 if (Table)
3979 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
3980 (Table << 8 & 0xFF0000);
3981
3982 if (!Buffer) Size = 0;
3983
3984 if (Buffer && Size)
3985 {
3986 FT_Error Error;
3987 FT_ULong Needed = 0;
3988
3989 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
3990
3991 if ( !Error && Needed < Size) Size = Needed;
3992 }
3993 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
3994 Result = Size;
3995 }
3996
3997 IntUnLockFreeType;
3998
3999 return Result;
4000 }
4001
4002 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
4003 static UINT
4004 GetFontPenalty(const LOGFONTW * LogFont,
4005 const OUTLINETEXTMETRICW * Otm,
4006 const char * style_name)
4007 {
4008 ULONG Penalty = 0;
4009 BYTE Byte;
4010 LONG Long;
4011 BOOL fNeedScaling = FALSE;
4012 const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
4013 const TEXTMETRICW * TM = &Otm->otmTextMetrics;
4014 WCHAR* ActualNameW;
4015
4016 ASSERT(Otm);
4017 ASSERT(LogFont);
4018 ASSERT(style_name);
4019
4020 /* FIXME: Aspect Penalty 30 */
4021 /* FIXME: IntSizeSynth Penalty 20 */
4022 /* FIXME: SmallPenalty Penalty 1 */
4023 /* FIXME: FaceNameSubst Penalty 500 */
4024
4025 Byte = LogFont->lfCharSet;
4026 if (Byte == DEFAULT_CHARSET)
4027 {
4028 if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0)
4029 {
4030 if (Byte == ANSI_CHARSET)
4031 {
4032 DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
4033 }
4034 /* We assume SYMBOL_CHARSET for "Marlett" font */
4035 Byte = SYMBOL_CHARSET;
4036 }
4037 }
4038
4039 if (Byte != TM->tmCharSet)
4040 {
4041 if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
4042 {
4043 /* CharSet Penalty 65000 */
4044 /* Requested charset does not match the candidate's. */
4045 Penalty += 65000;
4046 }
4047 else
4048 {
4049 if (UserCharSet != TM->tmCharSet)
4050 {
4051 /* UNDOCUMENTED */
4052 Penalty += 100;
4053 if (ANSI_CHARSET != TM->tmCharSet)
4054 {
4055 /* UNDOCUMENTED */
4056 Penalty += 100;
4057 }
4058 }
4059 }
4060 }
4061
4062 Byte = LogFont->lfOutPrecision;
4063 if (Byte == OUT_DEFAULT_PRECIS)
4064 Byte = OUT_OUTLINE_PRECIS; /* Is it OK? */
4065 switch (Byte)
4066 {
4067 case OUT_DEVICE_PRECIS:
4068 if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
4069 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
4070 {
4071 /* OutputPrecision Penalty 19000 */
4072 /* Requested OUT_STROKE_PRECIS, but the device can't do it
4073 or the candidate is not a vector font. */
4074 Penalty += 19000;
4075 }
4076 break;
4077 default:
4078 if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
4079 {
4080 /* OutputPrecision Penalty 19000 */
4081 /* Or OUT_STROKE_PRECIS not requested, and the candidate
4082 is a vector font that requires GDI support. */
4083 Penalty += 19000;
4084 }
4085 break;
4086 }
4087
4088 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4089 if (Byte == DEFAULT_PITCH)
4090 Byte = VARIABLE_PITCH;
4091 if (Byte == FIXED_PITCH)
4092 {
4093 if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
4094 {
4095 /* FixedPitch Penalty 15000 */
4096 /* Requested a fixed pitch font, but the candidate is a
4097 variable pitch font. */
4098 Penalty += 15000;
4099 }
4100 }
4101 if (Byte == VARIABLE_PITCH)
4102 {
4103 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4104 {
4105 /* PitchVariable Penalty 350 */
4106 /* Requested a variable pitch font, but the candidate is not a
4107 variable pitch font. */
4108 Penalty += 350;
4109 }
4110 }
4111
4112 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4113 if (Byte == DEFAULT_PITCH)
4114 {
4115 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4116 {
4117 /* DefaultPitchFixed Penalty 1 */
4118 /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
4119 Penalty += 1;
4120 }
4121 }
4122
4123 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
4124
4125 if (LogFont->lfFaceName[0])
4126 {
4127 BOOL Found = FALSE;
4128
4129 /* localized family name */
4130 if (!Found)
4131 {
4132 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4133 }
4134 /* localized full name */
4135 if (!Found)
4136 {
4137 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
4138 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4139 }
4140 if (!Found)
4141 {
4142 /* FaceName Penalty 10000 */
4143 /* Requested a face name, but the candidate's face name
4144 does not match. */
4145 Penalty += 10000;
4146 }
4147 }
4148
4149 Byte = (LogFont->lfPitchAndFamily & 0xF0);
4150 if (Byte != FF_DONTCARE)
4151 {
4152 if (Byte != (TM->tmPitchAndFamily & 0xF0))
4153 {
4154 /* Family Penalty 9000 */
4155 /* Requested a family, but the candidate's family is different. */
4156 Penalty += 9000;
4157 }
4158 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
4159 {
4160 /* FamilyUnknown Penalty 8000 */
4161 /* Requested a family, but the candidate has no family. */
4162 Penalty += 8000;
4163 }
4164 }
4165
4166 /* Is the candidate a non-vector font? */
4167 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4168 {
4169 /* Is lfHeight specified? */
4170 if (LogFont->lfHeight != 0)
4171 {
4172 if (labs(LogFont->lfHeight) < TM->tmHeight)
4173 {
4174 /* HeightBigger Penalty 600 */
4175 /* The candidate is a nonvector font and is bigger than the
4176 requested height. */
4177 Penalty += 600;
4178 /* HeightBiggerDifference Penalty 150 */
4179 /* The candidate is a raster font and is larger than the
4180 requested height. Penalty * height difference */
4181 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4182
4183 fNeedScaling = TRUE;
4184 }
4185 if (TM->tmHeight < labs(LogFont->lfHeight))
4186 {
4187 /* HeightSmaller Penalty 150 */
4188 /* The candidate is a raster font and is smaller than the
4189 requested height. Penalty * height difference */
4190 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4191
4192 fNeedScaling = TRUE;
4193 }
4194 }
4195 }
4196
4197 switch (LogFont->lfPitchAndFamily & 0xF0)
4198 {
4199 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4200 switch (TM->tmPitchAndFamily & 0xF0)
4201 {
4202 case FF_DECORATIVE: case FF_SCRIPT:
4203 /* FamilyUnlikely Penalty 50 */
4204 /* Requested a roman/modern/swiss family, but the
4205 candidate is decorative/script. */
4206 Penalty += 50;
4207 break;
4208 default:
4209 break;
4210 }
4211 break;
4212 case FF_DECORATIVE: case FF_SCRIPT:
4213 switch (TM->tmPitchAndFamily & 0xF0)
4214 {
4215 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4216 /* FamilyUnlikely Penalty 50 */
4217 /* Or requested decorative/script, and the candidate is
4218 roman/modern/swiss. */
4219 Penalty += 50;
4220 break;
4221 default:
4222 break;
4223 }
4224 default:
4225 break;
4226 }
4227
4228 if (LogFont->lfWidth != 0)
4229 {
4230 if (LogFont->lfWidth != TM->tmAveCharWidth)
4231 {
4232 /* Width Penalty 50 */
4233 /* Requested a nonzero width, but the candidate's width
4234 doesn't match. Penalty * width difference */
4235 Penalty += 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth);
4236
4237 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4238 fNeedScaling = TRUE;
4239 }
4240 }
4241
4242 if (fNeedScaling)
4243 {
4244 /* SizeSynth Penalty 50 */
4245 /* The candidate is a raster font that needs scaling by GDI. */
4246 Penalty += 50;
4247 }
4248
4249 if (!!LogFont->lfItalic != !!TM->tmItalic)
4250 {
4251 if (!LogFont->lfItalic && ItalicFromStyle(style_name))
4252 {
4253 /* Italic Penalty 4 */
4254 /* Requested font and candidate font do not agree on italic status,
4255 and the desired result cannot be simulated. */
4256 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
4257 Penalty += 40;
4258 }
4259 else if (LogFont->lfItalic && !ItalicFromStyle(style_name))
4260 {
4261 /* ItalicSim Penalty 1 */
4262 /* Requested italic font but the candidate is not italic,
4263 although italics can be simulated. */
4264 Penalty += 1;
4265 }
4266 }
4267
4268 if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
4269 {
4270 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
4271 {
4272 /* NotTrueType Penalty 4 */
4273 /* Requested OUT_TT_PRECIS, but the candidate is not a
4274 TrueType font. */
4275 Penalty += 4;
4276 }
4277 }
4278
4279 Long = LogFont->lfWeight;
4280 if (LogFont->lfWeight == FW_DONTCARE)
4281 Long = FW_NORMAL;
4282 if (Long != TM->tmWeight)
4283 {
4284 /* Weight Penalty 3 */
4285 /* The candidate's weight does not match the requested weight.
4286 Penalty * (weight difference/10) */
4287 Penalty += 3 * (labs(Long - TM->tmWeight) / 10);
4288 }
4289
4290 if (!LogFont->lfUnderline && TM->tmUnderlined)
4291 {
4292 /* Underline Penalty 3 */
4293 /* Requested font has no underline, but the candidate is
4294 underlined. */
4295 Penalty += 3;
4296 }
4297
4298 if (!LogFont->lfStrikeOut && TM->tmStruckOut)
4299 {
4300 /* StrikeOut Penalty 3 */
4301 /* Requested font has no strike-out, but the candidate is
4302 struck out. */
4303 Penalty += 3;
4304 }
4305
4306 /* Is the candidate a non-vector font? */
4307 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4308 {
4309 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
4310 {
4311 /* VectorHeightSmaller Penalty 2 */
4312 /* Candidate is a vector font that is smaller than the
4313 requested height. Penalty * height difference */
4314 Penalty += 2 * labs(TM->tmHeight - LogFont->lfHeight);
4315 }
4316 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
4317 {
4318 /* VectorHeightBigger Penalty 1 */
4319 /* Candidate is a vector font that is bigger than the
4320 requested height. Penalty * height difference */
4321 Penalty += 1 * labs(TM->tmHeight - LogFont->lfHeight);
4322 }
4323 }
4324
4325 if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
4326 {
4327 /* DeviceFavor Penalty 2 */
4328 /* Extra penalty for all nondevice fonts. */
4329 Penalty += 2;
4330 }
4331
4332 if (Penalty < 200)
4333 {
4334 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
4335 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
4336 "tmCharSet:%d, tmWeight:%ld\n",
4337 Penalty, LogFont->lfFaceName, ActualNameW,
4338 LogFont->lfCharSet, LogFont->lfWeight,
4339 TM->tmCharSet, TM->tmWeight);
4340 }
4341
4342 return Penalty; /* success */
4343 }
4344
4345 static __inline VOID
4346 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
4347 const LOGFONTW *LogFont,
4348 const PLIST_ENTRY Head)
4349 {
4350 ULONG Penalty;
4351 PLIST_ENTRY Entry;
4352 PFONT_ENTRY CurrentEntry;
4353 FONTGDI *FontGDI;
4354 OUTLINETEXTMETRICW *Otm = NULL;
4355 UINT OtmSize, OldOtmSize = 0;
4356 FT_Face Face;
4357
4358 ASSERT(FontObj);
4359 ASSERT(MatchPenalty);
4360 ASSERT(LogFont);
4361 ASSERT(Head);
4362
4363 /* Start with a pretty big buffer */
4364 OldOtmSize = 0x200;
4365 Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
4366
4367 /* get the FontObj of lowest penalty */
4368 Entry = Head->Flink;
4369 while (Entry != Head)
4370 {
4371 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
4372 Entry = Entry->Flink;
4373
4374 FontGDI = CurrentEntry->Font;
4375 ASSERT(FontGDI);
4376 Face = FontGDI->SharedFace->Face;
4377
4378 /* get text metrics */
4379 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4380 if (OtmSize > OldOtmSize)
4381 {
4382 if (Otm)
4383 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4384 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
4385 }
4386
4387 /* update FontObj if lowest penalty */
4388 if (Otm)
4389 {
4390 OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
4391 if (!OtmSize)
4392 continue;
4393
4394 OldOtmSize = OtmSize;
4395
4396 Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
4397 if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
4398 {
4399 *FontObj = GDIToObj(FontGDI, FONT);
4400 *MatchPenalty = Penalty;
4401 }
4402 }
4403 }
4404
4405 if (Otm)
4406 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4407 }
4408
4409 static
4410 VOID
4411 FASTCALL
4412 IntFontType(PFONTGDI Font)
4413 {
4414 PS_FontInfoRec psfInfo;
4415 FT_ULong tmp_size = 0;
4416 FT_Face Face = Font->SharedFace->Face;
4417
4418 if (FT_HAS_MULTIPLE_MASTERS(Face))
4419 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
4420 if (FT_HAS_VERTICAL(Face))
4421 Font->FontObj.flFontType |= FO_VERT_FACE;
4422 if (!FT_IS_SCALABLE(Face))
4423 Font->FontObj.flFontType |= FO_TYPE_RASTER;
4424 if (FT_IS_SFNT(Face))
4425 {
4426 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
4427 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
4428 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4429 }
4430 if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
4431 {
4432 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4433 }
4434 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
4435 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
4436 {
4437 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
4438 }
4439 }
4440
4441 NTSTATUS
4442 FASTCALL
4443 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
4444 {
4445 NTSTATUS Status = STATUS_SUCCESS;
4446 PTEXTOBJ TextObj;
4447 PPROCESSINFO Win32Process;
4448 ULONG MatchPenalty;
4449 LOGFONTW *pLogFont;
4450 LOGFONTW SubstitutedLogFont;
4451 FT_Face Face;
4452
4453 if (!pTextObj)
4454 {
4455 TextObj = TEXTOBJ_LockText(FontHandle);
4456 if (NULL == TextObj)
4457 {
4458 return STATUS_INVALID_HANDLE;
4459 }
4460
4461 if (TextObj->fl & TEXTOBJECT_INIT)
4462 {
4463 TEXTOBJ_UnlockText(TextObj);
4464 return STATUS_SUCCESS;
4465 }
4466 }
4467 else
4468 {
4469 TextObj = pTextObj;
4470 }
4471
4472 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4473
4474 /* substitute */
4475 SubstitutedLogFont = *pLogFont;
4476 DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
4477 SubstituteFontRecurse(&SubstitutedLogFont);
4478 DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
4479
4480 MatchPenalty = 0xFFFFFFFF;
4481 TextObj->Font = NULL;
4482
4483 Win32Process = PsGetCurrentProcessWin32Process();
4484
4485 /* Search private fonts */
4486 IntLockProcessPrivateFonts(Win32Process);
4487 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4488 &Win32Process->PrivateFontListHead);
4489 IntUnLockProcessPrivateFonts(Win32Process);
4490
4491 /* Search system fonts */
4492 IntLockGlobalFonts;
4493 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4494 &FontListHead);
4495 IntUnLockGlobalFonts;
4496
4497 if (NULL == TextObj->Font)
4498 {
4499 DPRINT1("Request font %S not found, no fonts loaded at all\n",
4500 pLogFont->lfFaceName);
4501 Status = STATUS_NOT_FOUND;
4502 }
4503 else
4504 {
4505 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
4506 // Need hdev, when freetype is loaded need to create DEVOBJ for
4507 // Consumer and Producer.
4508 TextObj->Font->iUniq = 1; // Now it can be cached.
4509 IntFontType(FontGdi);
4510 FontGdi->flType = TextObj->Font->flFontType;
4511 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
4512 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
4513 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
4514 if (pLogFont->lfWeight != FW_DONTCARE)
4515 FontGdi->RequestWeight = pLogFont->lfWeight;
4516 else
4517 FontGdi->RequestWeight = FW_NORMAL;
4518
4519 Face = FontGdi->SharedFace->Face;
4520
4521 //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name);
4522
4523 if (!FontGdi->OriginalItalic)
4524 FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name);
4525
4526 TextObj->fl |= TEXTOBJECT_INIT;
4527 Status = STATUS_SUCCESS;
4528 }
4529
4530 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
4531
4532 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
4533
4534 return Status;
4535 }
4536
4537
4538 static
4539 BOOL
4540 FASTCALL
4541 IntGetFullFileName(
4542 POBJECT_NAME_INFORMATION NameInfo,
4543 ULONG Size,
4544 PUNICODE_STRING FileName)
4545 {
4546 NTSTATUS Status;
4547 OBJECT_ATTRIBUTES ObjectAttributes;
4548 HANDLE hFile;
4549 IO_STATUS_BLOCK IoStatusBlock;
4550 ULONG Desired;
4551
4552 InitializeObjectAttributes(&ObjectAttributes,
4553 FileName,
4554 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
4555 NULL,
4556 NULL);
4557
4558 Status = ZwOpenFile(
4559 &hFile,
4560 0, // FILE_READ_ATTRIBUTES,
4561 &ObjectAttributes,
4562 &IoStatusBlock,
4563 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4564 0);
4565
4566 if (!NT_SUCCESS(Status))
4567 {
4568 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
4569 return FALSE;
4570 }
4571
4572 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
4573 ZwClose(hFile);
4574 if (!NT_SUCCESS(Status))
4575 {
4576 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
4577 return FALSE;
4578 }
4579
4580 return TRUE;
4581 }
4582
4583 static BOOL
4584 EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2)
4585 {
4586 const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
4587 const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
4588 const LOGFONTW *plf1 = &pLog1->elfLogFont;
4589 const LOGFONTW *plf2 = &pLog2->elfLogFont;
4590
4591 if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0)
4592 {
4593 return FALSE;
4594 }
4595
4596 if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0)
4597 {
4598 return FALSE;
4599 }
4600
4601 return TRUE;
4602 }
4603
4604 static VOID
4605 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
4606 {
4607 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
4608 if (FamInfo->EnumLogFontEx.elfStyle[0] &&
4609 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
4610 {
4611 wcscat(psz, L" ");
4612 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
4613 }
4614 }
4615
4616 BOOL
4617 FASTCALL
4618 IntGdiGetFontResourceInfo(
4619 PUNICODE_STRING FileName,
4620 PVOID pBuffer,
4621 DWORD *pdwBytes,
4622 DWORD dwType)
4623 {
4624 UNICODE_STRING EntryFileName;
4625 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
4626 PLIST_ENTRY ListEntry;
4627 PFONT_ENTRY FontEntry;
4628 ULONG Size, i, Count;
4629 LPBYTE pbBuffer;
4630 BOOL IsEqual;
4631 FONTFAMILYINFO *FamInfo;
4632 const ULONG MaxFamInfo = 64;
4633 BOOL bSuccess;
4634
4635 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
4636
4637 /* Create buffer for full path name */
4638 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
4639 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4640 if (!NameInfo1)
4641 {
4642 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4643 return FALSE;
4644 }
4645
4646 /* Get the full path name */
4647 if (!IntGetFullFileName(NameInfo1, Size, FileName))
4648 {
4649 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4650 return FALSE;
4651 }
4652
4653 /* Create a buffer for the entries' names */
4654 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4655 if (!NameInfo2)
4656 {
4657 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4658 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4659 return FALSE;
4660 }
4661
4662 FamInfo = ExAllocatePoolWithTag(PagedPool,
4663 sizeof(FONTFAMILYINFO) * MaxFamInfo,
4664 TAG_FINF);
4665 if (!FamInfo)
4666 {
4667 ExFreePoolWithTag(NameInfo2, TAG_FINF);
4668 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4669 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4670 return FALSE;
4671 }
4672 /* Try to find the pathname in the global font list */
4673 Count = 0;
4674 IntLockGlobalFonts;
4675 for (ListEntry = FontListHead.Flink; ListEntry != &FontListHead;
4676 ListEntry = ListEntry->Flink)
4677 {
4678 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
4679 if (FontEntry->Font->Filename == NULL)
4680 continue;
4681
4682 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
4683 if (!IntGetFullFileName(NameInfo2, Size, &EntryFileName))
4684 continue;
4685
4686 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
4687 continue;
4688
4689 IsEqual = FALSE;
4690 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
4691 NULL, FontEntry->Font);
4692 for (i = 0; i < Count; ++i)
4693 {
4694 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
4695 {
4696 IsEqual = TRUE;
4697 break;
4698 }
4699 }
4700 if (!IsEqual)
4701 {
4702 /* Found */
4703 ++Count;
4704 if (Count >= MaxFamInfo)
4705 break;
4706 }
4707 }
4708 IntUnLockGlobalFonts;
4709
4710 /* Free the buffers */
4711 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4712 ExFreePool(NameInfo2);
4713
4714 if (Count == 0 && dwType != 5)
4715 {
4716 /* Font could not be found in system table
4717 dwType == 5 will still handle this */
4718 ExFreePoolWithTag(FamInfo, TAG_FINF);
4719 return FALSE;
4720 }
4721
4722 bSuccess = FALSE;
4723 switch (dwType)
4724 {
4725 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
4726 Size = sizeof(DWORD);
4727 if (*pdwBytes == 0)
4728 {
4729 *pdwBytes = Size;
4730 bSuccess = TRUE;
4731 }
4732 else if (pBuffer)
4733 {
4734 if (*pdwBytes >= Size)
4735 {
4736 *(DWORD*)pBuffer = Count;
4737 }
4738 *pdwBytes = Size;
4739 bSuccess = TRUE;
4740 }
4741 break;
4742
4743 case 1: /* copy the font title */
4744 /* calculate the required size */
4745 Size = 0;
4746 Size += wcslen(FamInfo[0].EnumLogFontEx.elfLogFont.lfFaceName);
4747 if (FamInfo[0].EnumLogFontEx.elfStyle[0] &&
4748 _wcsicmp(FamInfo[0].EnumLogFontEx.elfStyle, L"Regular") != 0)
4749 {
4750 Size += 1 + wcslen(FamInfo[0].EnumLogFontEx.elfStyle);
4751 }
4752 for (i = 1; i < Count; ++i)
4753 {
4754 Size += 3; /* " & " */
4755 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
4756 if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
4757 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
4758 {
4759 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
4760 }
4761 }
4762 Size += 2; /* "\0\0" */
4763 Size *= sizeof(WCHAR);
4764
4765 if (*pdwBytes == 0)
4766 {
4767 *pdwBytes = Size;
4768 bSuccess = TRUE;
4769 }
4770 else if (pBuffer)
4771 {
4772 if (*pdwBytes >= Size)
4773 {
4774 /* store font title to buffer */
4775 WCHAR *psz = pBuffer;
4776 *psz = 0;
4777 IntAddNameFromFamInfo(psz, &FamInfo[0]);
4778 for (i = 1; i < Count; ++i)
4779 {
4780 wcscat(psz, L" & ");
4781 IntAddNameFromFamInfo(psz, &FamInfo[i]);
4782 }
4783 psz[wcslen(psz) + 1] = UNICODE_NULL;
4784 *pdwBytes = Size;
4785 bSuccess = TRUE;
4786 }
4787 else
4788 {
4789 *pdwBytes = 1024; /* this is confirmed value */
4790 }
4791 }
4792 break;
4793
4794 case 2: /* Copy an array of LOGFONTW */
4795 Size = Count * sizeof(LOGFONTW);
4796 if (*pdwBytes == 0)
4797 {
4798 *pdwBytes = Size;
4799 bSuccess = TRUE;
4800 }
4801 else if (pBuffer)
4802 {
4803 if (*pdwBytes >= Size)
4804 {
4805 pbBuffer = (LPBYTE)pBuffer;
4806 for (i = 0; i < Count; ++i)
4807 {
4808 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
4809 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
4810 pbBuffer += sizeof(LOGFONTW);
4811 }
4812 }
4813 *pdwBytes = Size;
4814 bSuccess = TRUE;
4815 }
4816 else
4817 {
4818 *pdwBytes = 1024; /* this is confirmed value */
4819 }
4820 break;
4821
4822 case 3:
4823 Size = sizeof(DWORD);
4824 if (*pdwBytes == 0)
4825 {
4826 *pdwBytes = Size;
4827 bSuccess = TRUE;
4828 }
4829 else if (pBuffer)
4830 {
4831 if (*pdwBytes >= Size)
4832 {
4833 /* FIXME: What exactly is copied here? */
4834 *(DWORD*)pBuffer = 1;
4835 }
4836 *pdwBytes = Size;
4837 bSuccess = TRUE;
4838 }
4839 break;
4840
4841 case 4: /* full file path */
4842 if (FileName->Length >= 4 * sizeof(WCHAR))
4843 {
4844 /* The beginning of FileName is \??\ */
4845 LPWSTR pch = FileName->Buffer + 4;
4846 DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
4847
4848 Size = Length + sizeof(WCHAR);
4849 if (*pdwBytes == 0)
4850 {
4851 *pdwBytes = Size;
4852 bSuccess = TRUE;
4853 }
4854 else if (pBuffer)
4855 {
4856 if (*pdwBytes >= Size)
4857 {
4858 RtlCopyMemory(pBuffer, pch, Size);
4859 }
4860 *pdwBytes = Size;
4861 bSuccess = TRUE;
4862 }
4863 }
4864 break;
4865
4866 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
4867 Size = sizeof(BOOL);
4868 if (*pdwBytes == 0)
4869 {
4870 *pdwBytes = Size;
4871 bSuccess = TRUE;
4872 }
4873 else if (pBuffer)
4874 {
4875 if (*pdwBytes >= Size)
4876 {
4877 *(BOOL*)pBuffer = Count == 0;
4878 }
4879 *pdwBytes = Size;
4880 bSuccess = TRUE;
4881 }
4882 break;
4883 }
4884 ExFreePoolWithTag(FamInfo, TAG_FINF);
4885
4886 return bSuccess;
4887 }
4888
4889
4890 BOOL
4891 FASTCALL
4892 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
4893 {
4894 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
4895 Info->iTechnology = RI_TECH_BITMAP;
4896 else
4897 {
4898 if (FT_IS_SCALABLE(Font->SharedFace->Face))
4899 Info->iTechnology = RI_TECH_SCALABLE;
4900 else
4901 Info->iTechnology = RI_TECH_FIXED;
4902 }
4903 Info->iUniq = Font->FontObj.iUniq;
4904 Info->dwUnknown = -1;
4905 return TRUE;
4906 }
4907
4908
4909 DWORD
4910 FASTCALL
4911 ftGdiGetKerningPairs( PFONTGDI Font,
4912 DWORD cPairs,
4913 LPKERNINGPAIR pKerningPair)
4914 {
4915 DWORD Count = 0;
4916 INT i = 0;
4917 FT_Face face = Font->SharedFace->Face;
4918
4919 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
4920 {
4921 FT_UInt previous_index = 0, glyph_index = 0;
4922 FT_ULong char_code, char_previous;
4923 FT_Vector delta;
4924
4925 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
4926
4927 IntLockFreeType;
4928
4929 while (glyph_index)
4930 {
4931 if (previous_index && glyph_index)
4932 {
4933 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
4934
4935 if (pKerningPair && cPairs)
4936 {
4937 pKerningPair[i].wFirst = char_previous;
4938 pKerningPair[i].wSecond = char_code;
4939 pKerningPair[i].iKernAmount = delta.x;
4940 i++;
4941 if (i == cPairs) break;
4942 }
4943 Count++;
4944 }
4945 previous_index = glyph_index;
4946 char_previous = char_code;
4947 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
4948 }
4949 IntUnLockFreeType;
4950 }
4951 return Count;
4952 }
4953
4954
4955 ///////////////////////////////////////////////////////////////////////////
4956 //
4957 // Functions needing sorting.
4958 //
4959 ///////////////////////////////////////////////////////////////////////////
4960 int APIENTRY
4961 NtGdiGetFontFamilyInfo(HDC Dc,
4962 LPLOGFONTW UnsafeLogFont,
4963 PFONTFAMILYINFO UnsafeInfo,
4964 DWORD Size)
4965 {
4966 NTSTATUS Status;
4967 LOGFONTW LogFont;
4968 PFONTFAMILYINFO Info;
4969 DWORD Count;
4970 PPROCESSINFO Win32Process;
4971
4972 /* Make a safe copy */
4973 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
4974 if (! NT_SUCCESS(Status))
4975 {
4976 EngSetLastError(ERROR_INVALID_PARAMETER);
4977 return -1;
4978 }
4979
4980 /* Allocate space for a safe copy */
4981 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT);
4982 if (NULL == Info)
4983 {
4984 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4985 return -1;
4986 }
4987
4988 /* Enumerate font families in the global list */
4989 IntLockGlobalFonts;
4990 Count = 0;
4991 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
4992 {
4993 IntUnLockGlobalFonts;
4994 ExFreePoolWithTag(Info, GDITAG_TEXT);
4995 return -1;
4996 }
4997 IntUnLockGlobalFonts;
4998
4999 /* Enumerate font families in the process local list */
5000 Win32Process = PsGetCurrentProcessWin32Process();
5001 IntLockProcessPrivateFonts(Win32Process);
5002 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
5003 &Win32Process->PrivateFontListHead))
5004 {
5005 IntUnLockProcessPrivateFonts(Win32Process);
5006 ExFreePoolWithTag(Info, GDITAG_TEXT);
5007 return -1;
5008 }
5009 IntUnLockProcessPrivateFonts(Win32Process);
5010
5011 /* Enumerate font families in the registry */
5012 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
5013 {
5014 ExFreePoolWithTag(Info, GDITAG_TEXT);
5015 return -1;
5016 }
5017
5018 /* Return data to caller */
5019 if (0 != Count)
5020 {
5021 Status = MmCopyToCaller(UnsafeInfo, Info,
5022 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
5023 if (! NT_SUCCESS(Status))
5024 {
5025 ExFreePoolWithTag(Info, GDITAG_TEXT);
5026 EngSetLastError(ERROR_INVALID_PARAMETER);
5027 return -1;
5028 }
5029 }
5030
5031 ExFreePoolWithTag(Info, GDITAG_TEXT);
5032
5033 return Count;
5034 }
5035
5036 FORCEINLINE
5037 LONG
5038 ScaleLong(LONG lValue, PFLOATOBJ pef)
5039 {
5040 FLOATOBJ efTemp;
5041
5042 /* Check if we have scaling different from 1 */
5043 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
5044 {
5045 /* Need to multiply */
5046 FLOATOBJ_SetLong(&efTemp, lValue);
5047 FLOATOBJ_Mul(&efTemp, pef);
5048 lValue = FLOATOBJ_GetLong(&efTemp);
5049 }
5050
5051 return lValue;
5052 }
5053
5054 BOOL
5055 APIENTRY
5056 GreExtTextOutW(
5057 IN HDC hDC,
5058 IN INT XStart,
5059 IN INT YStart,
5060 IN UINT fuOptions,
5061 IN OPTIONAL PRECTL lprc,
5062 IN LPCWSTR String,
5063 IN INT Count,
5064 IN OPTIONAL LPINT Dx,
5065 IN DWORD dwCodePage)
5066 {
5067 /*
5068 * FIXME:
5069 * Call EngTextOut, which does the real work (calling DrvTextOut where
5070 * appropriate)
5071 */
5072
5073 DC *dc;
5074 PDC_ATTR pdcattr;
5075 SURFOBJ *SurfObj;
5076 SURFACE *psurf = NULL;
5077 int error, glyph_index, i;
5078 FT_Face face;
5079 FT_GlyphSlot glyph;
5080 FT_BitmapGlyph realglyph;
5081 LONGLONG TextLeft, RealXStart;
5082 ULONG TextTop, previous, BackgroundLeft;
5083 FT_Bool use_kerning;
5084 RECTL DestRect, MaskRect;
5085 POINTL SourcePoint, BrushOrigin;
5086 HBITMAP HSourceGlyph;
5087 SURFOBJ *SourceGlyphSurf;
5088 SIZEL bitSize;
5089 INT yoff;
5090 FONTOBJ *FontObj;
5091 PFONTGDI FontGDI;
5092 PTEXTOBJ TextObj = NULL;
5093 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
5094 FT_Render_Mode RenderMode;
5095 BOOLEAN Render;
5096 POINT Start;
5097 BOOL DoBreak = FALSE;
5098 USHORT DxShift;
5099 PMATRIX pmxWorldToDevice;
5100 LONG fixAscender, fixDescender;
5101 FLOATOBJ Scale;
5102 LOGFONTW *plf;
5103 BOOL EmuBold, EmuItalic;
5104 int thickness;
5105 BOOL bResult;
5106
5107 /* Check if String is valid */
5108 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
5109 {
5110 EngSetLastError(ERROR_INVALID_PARAMETER);
5111 return FALSE;
5112 }
5113
5114 // TODO: Write test-cases to exactly match real Windows in different
5115 // bad parameters (e.g. does Windows check the DC or the RECT first?).
5116 dc = DC_LockDc(hDC);
5117 if (!dc)
5118 {
5119 EngSetLastError(ERROR_INVALID_HANDLE);
5120 return FALSE;
5121 }
5122
5123 if (PATH_IsPathOpen(dc->dclevel))
5124 {
5125 bResult = PATH_ExtTextOut(dc,
5126 XStart,
5127 YStart,
5128 fuOptions,
5129 (const RECTL *)lprc,
5130 String,
5131 Count,
5132 (const INT *)Dx);
5133 DC_UnlockDc(dc);
5134 return bResult;
5135 }
5136
5137 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
5138
5139 if (!dc->dclevel.pSurface)
5140 {
5141 /* Memory DC with no surface selected */
5142 bResult = FALSE; // TRUE?
5143 goto Cleanup;
5144 }
5145
5146 pdcattr = dc->pdcattr;
5147
5148 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
5149 {
5150 IntLPtoDP(dc, (POINT *)lprc, 2);
5151 }
5152
5153 if (pdcattr->lTextAlign & TA_UPDATECP)
5154 {
5155 Start.x = pdcattr->ptlCurrent.x;
5156 Start.y = pdcattr->ptlCurrent.y;
5157 } else {
5158 Start.x = XStart;
5159 Start.y = YStart;
5160 }
5161
5162 IntLPtoDP(dc, &Start, 1);
5163 RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
5164 YStart = Start.y + dc->ptlDCOrig.y;
5165
5166 SourcePoint.x = 0;
5167 SourcePoint.y = 0;
5168 MaskRect.left = 0;
5169 MaskRect.top = 0;
5170 BrushOrigin.x = 0;
5171 BrushOrigin.y = 0;
5172
5173 if ((fuOptions & ETO_OPAQUE) && lprc)
5174 {
5175 DestRect.left = lprc->left;
5176 DestRect.top = lprc->top;
5177 DestRect.right = lprc->right;
5178 DestRect.bottom = lprc->bottom;
5179
5180 DestRect.left += dc->ptlDCOrig.x;
5181 DestRect.top += dc->ptlDCOrig.y;
5182 DestRect.right += dc->ptlDCOrig.x;
5183 DestRect.bottom += dc->ptlDCOrig.y;
5184
5185 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5186 {
5187 IntUpdateBoundsRect(dc, &DestRect);
5188 }
5189
5190 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5191 DC_vUpdateBackgroundBrush(dc);
5192 if (dc->dctype == DCTYPE_DIRECT)
5193 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5194
5195 psurf = dc->dclevel.pSurface;
5196 IntEngBitBlt(
5197 &psurf->SurfObj,
5198 NULL,
5199 NULL,
5200 (CLIPOBJ *)&dc->co,
5201 NULL,
5202 &DestRect,
5203 &SourcePoint,
5204 &SourcePoint,
5205 &dc->eboBackground.BrushObject,
5206 &BrushOrigin,
5207 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5208
5209 if (dc->dctype == DCTYPE_DIRECT)
5210 MouseSafetyOnDrawEnd(dc->ppdev);
5211
5212 fuOptions &= ~ETO_OPAQUE;
5213 }
5214 else
5215 {
5216 if (pdcattr->jBkMode == OPAQUE)
5217 {
5218 fuOptions |= ETO_OPAQUE;
5219 }
5220 }
5221
5222 TextObj = RealizeFontInit(pdcattr->hlfntNew);
5223 if (TextObj == NULL)
5224 {
5225 bResult = FALSE;
5226 goto Cleanup;
5227 }
5228
5229 FontObj = TextObj->Font;
5230 ASSERT(FontObj);
5231 FontGDI = ObjToGDI(FontObj, FONT);
5232 ASSERT(FontGDI);
5233
5234 IntLockFreeType;
5235 face = FontGDI->SharedFace->Face;
5236
5237 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5238 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
5239 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
5240
5241 Render = IntIsFontRenderingEnabled();
5242 if (Render)
5243 RenderMode = IntGetFontRenderMode(plf);
5244 else
5245 RenderMode = FT_RENDER_MODE_MONO;
5246
5247 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
5248 {
5249 IntUnLockFreeType;
5250 bResult = FALSE;
5251 goto Cleanup;
5252 }
5253
5254 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
5255 {
5256 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
5257 FtSetCoordinateTransform(face, pmxWorldToDevice);
5258
5259 fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
5260 fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
5261 }
5262 else
5263 {
5264 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
5265 FtSetCoordinateTransform(face, pmxWorldToDevice);
5266
5267 fixAscender = face->size->metrics.ascender;
5268 fixDescender = face->size->metrics.descender;
5269 }
5270
5271 /*
5272 * Process the vertical alignment and determine the yoff.
5273 */
5274
5275 if (pdcattr->lTextAlign & TA_BASELINE)
5276 yoff = 0;
5277 else if (pdcattr->lTextAlign & TA_BOTTOM)
5278 yoff = -fixDescender >> 6;
5279 else /* TA_TOP */
5280 yoff = fixAscender >> 6;
5281
5282 use_kerning = FT_HAS_KERNING(face);
5283 previous = 0;
5284
5285 /*
5286 * Process the horizontal alignment and modify XStart accordingly.
5287 */
5288 DxShift = fuOptions & ETO_PDY ? 1 : 0;
5289 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
5290 {
5291 ULONGLONG TextWidth = 0;
5292 LPCWSTR TempText = String;
5293 int iStart;
5294
5295 /*
5296 * Calculate width of the text.
5297 */
5298
5299 if (NULL != Dx)
5300 {
5301 iStart = Count < 2 ? 0 : Count - 2;
5302 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
5303 }
5304 else
5305 {
5306 iStart = 0;
5307 }
5308 TempText = String + iStart;
5309
5310 for (i = iStart; i < Count; i++)
5311 {
5312 if (fuOptions & ETO_GLYPH_INDEX)
5313 glyph_index = *TempText;
5314 else
5315 glyph_index = FT_Get_Char_Index(face, *TempText);
5316
5317 if (EmuBold || EmuItalic)
5318 realglyph = NULL;
5319 else
5320 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
5321 plf->lfHeight, pmxWorldToDevice);
5322 if (!realglyph)
5323 {
5324 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5325 if (error)
5326 {
5327 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
5328 }
5329
5330 glyph = face->glyph;
5331 if (EmuBold || EmuItalic)
5332 {
5333 if (EmuBold)
5334 FT_GlyphSlot_Embolden(glyph);
5335 if (EmuItalic)
5336 FT_GlyphSlot_Oblique(glyph);
5337 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5338 }
5339 else
5340 {
5341 realglyph = ftGdiGlyphCacheSet(face,
5342 glyph_index,
5343 plf->lfHeight,
5344 pmxWorldToDevice,
5345 glyph,
5346 RenderMode);
5347 }
5348 if (!realglyph)
5349 {
5350 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5351 IntUnLockFreeType;
5352 goto Cleanup;
5353 }
5354
5355 }
5356 /* Retrieve kerning distance */
5357 if (use_kerning && previous && glyph_index)
5358 {
5359 FT_Vector delta;
5360 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5361 TextWidth += delta.x;
5362 }
5363
5364 TextWidth += realglyph->root.advance.x >> 10;
5365
5366 if (EmuBold || EmuItalic)
5367 {
5368 FT_Done_Glyph((FT_Glyph)realglyph);
5369 realglyph = NULL;
5370 }
5371
5372 previous = glyph_index;
5373 TempText++;
5374 }
5375
5376 previous = 0;
5377
5378 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
5379 {
5380 RealXStart -= TextWidth / 2;
5381 }
5382 else
5383 {
5384 RealXStart -= TextWidth;
5385 }
5386 }
5387
5388 psurf = dc->dclevel.pSurface;
5389 SurfObj = &psurf->SurfObj ;
5390
5391 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
5392 DC_vUpdateBackgroundBrush(dc) ;
5393
5394 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
5395 DC_vUpdateTextBrush(dc) ;
5396
5397 if (!face->units_per_EM)
5398 {
5399 thickness = 1;
5400 }
5401 else
5402 {
5403 thickness = face->underline_thickness *
5404 face->size->metrics.y_ppem / face->units_per_EM;
5405 if (thickness <= 0)
5406 thickness = 1;
5407 }
5408
5409 if ((fuOptions & ETO_OPAQUE) && plf->lfItalic)
5410 {
5411 /* Draw background */
5412 TextLeft = RealXStart;
5413 TextTop = YStart;
5414 BackgroundLeft = (RealXStart + 32) >> 6;
5415 for (i = 0; i < Count; ++i)
5416 {
5417 if (fuOptions & ETO_GLYPH_INDEX)
5418 glyph_index = String[i];
5419 else
5420 glyph_index = FT_Get_Char_Index(face, String[i]);
5421
5422 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5423 if (error)
5424 {
5425 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5426 IntUnLockFreeType;
5427 goto Cleanup;
5428 }
5429
5430 glyph = face->glyph;
5431 if (EmuBold)
5432 FT_GlyphSlot_Embolden(glyph);
5433 if (EmuItalic)
5434 FT_GlyphSlot_Oblique(glyph);
5435 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5436 if (!realglyph)
5437 {
5438 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5439 IntUnLockFreeType;
5440 goto Cleanup;
5441 }
5442
5443 /* retrieve kerning distance and move pen position */
5444 if (use_kerning && previous && glyph_index && NULL == Dx)
5445 {
5446 FT_Vector delta;
5447 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5448 TextLeft += delta.x;
5449 }
5450 DPRINT("TextLeft: %I64d\n", TextLeft);
5451 DPRINT("TextTop: %lu\n", TextTop);
5452 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5453
5454 DestRect.left = BackgroundLeft;
5455 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5456 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5457 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5458 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5459 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5460 {
5461 IntUpdateBoundsRect(dc, &DestRect);
5462 }
5463 IntEngBitBlt(
5464 &psurf->SurfObj,
5465 NULL,
5466 NULL,
5467 (CLIPOBJ *)&dc->co,
5468 NULL,
5469 &DestRect,
5470 &SourcePoint,
5471 &SourcePoint,
5472 &dc->eboBackground.BrushObject,
5473 &BrushOrigin,
5474 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5475 MouseSafetyOnDrawEnd(dc->ppdev);
5476 BackgroundLeft = DestRect.right;
5477
5478 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5479 DestRect.right = DestRect.left + realglyph->bitmap.width;
5480 DestRect.top = TextTop + yoff - realglyph->top;
5481 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5482
5483 bitSize.cx = realglyph->bitmap.width;
5484 bitSize.cy = realglyph->bitmap.rows;
5485 MaskRect.right = realglyph->bitmap.width;
5486 MaskRect.bottom = realglyph->bitmap.rows;
5487
5488 if (NULL == Dx)
5489 {
5490 TextLeft += realglyph->root.advance.x >> 10;
5491 DPRINT("New TextLeft: %I64d\n", TextLeft);
5492 }
5493 else
5494 {
5495 // FIXME this should probably be a matrix transform with TextTop as well.
5496 Scale = pdcattr->mxWorldToDevice.efM11;
5497 if (FLOATOBJ_Equal0(&Scale))
5498 FLOATOBJ_Set1(&Scale);
5499
5500 /* do the shift before multiplying to preserve precision */
5501 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5502 TextLeft += FLOATOBJ_GetLong(&Scale);
5503 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5504 }
5505
5506 if (DxShift)
5507 {
5508 TextTop -= Dx[2 * i + 1] << 6;
5509 }
5510
5511 previous = glyph_index;
5512
5513 if (EmuBold || EmuItalic)
5514 {
5515 FT_Done_Glyph((FT_Glyph)realglyph);
5516 realglyph = NULL;
5517 }
5518 }
5519 }
5520
5521 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
5522 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
5523
5524 /* Assume success */
5525 bResult = TRUE;
5526
5527 /*
5528 * The main rendering loop.
5529 */
5530 TextLeft = RealXStart;
5531 TextTop = YStart;
5532 BackgroundLeft = (RealXStart + 32) >> 6;
5533 for (i = 0; i < Count; ++i)
5534 {
5535 if (fuOptions & ETO_GLYPH_INDEX)
5536 glyph_index = String[i];
5537 else
5538 glyph_index = FT_Get_Char_Index(face, String[i]);
5539
5540 if (EmuBold || EmuItalic)
5541 realglyph = NULL;
5542 else
5543 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
5544 plf->lfHeight, pmxWorldToDevice);
5545 if (!realglyph)
5546 {
5547 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5548 if (error)
5549 {
5550 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5551 bResult = FALSE;
5552 break;
5553 }
5554
5555 glyph = face->glyph;
5556 if (EmuBold || EmuItalic)
5557 {
5558 if (EmuBold)
5559 FT_GlyphSlot_Embolden(glyph);
5560 if (EmuItalic)
5561 FT_GlyphSlot_Oblique(glyph);
5562 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5563 }
5564 else
5565 {
5566 realglyph = ftGdiGlyphCacheSet(face,
5567 glyph_index,
5568 plf->lfHeight,
5569 pmxWorldToDevice,
5570 glyph,
5571 RenderMode);
5572 }
5573 if (!realglyph)
5574 {
5575 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5576 bResult = FALSE;
5577 break;
5578 }
5579 }
5580
5581 /* retrieve kerning distance and move pen position */
5582 if (use_kerning && previous && glyph_index && NULL == Dx)
5583 {
5584 FT_Vector delta;
5585 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5586 TextLeft += delta.x;
5587 }
5588 DPRINT("TextLeft: %I64d\n", TextLeft);
5589 DPRINT("TextTop: %lu\n", TextTop);
5590 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5591
5592 if ((fuOptions & ETO_OPAQUE) && !plf->lfItalic)
5593 {
5594 DestRect.left = BackgroundLeft;
5595 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5596 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5597 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5598
5599 if (dc->dctype == DCTYPE_DIRECT)
5600 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5601
5602 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5603 {
5604 IntUpdateBoundsRect(dc, &DestRect);
5605 }
5606 IntEngBitBlt(
5607 &psurf->SurfObj,
5608 NULL,
5609 NULL,
5610 (CLIPOBJ *)&dc->co,
5611 NULL,
5612 &DestRect,
5613 &SourcePoint,
5614 &SourcePoint,
5615 &dc->eboBackground.BrushObject,
5616 &BrushOrigin,
5617 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5618
5619 if (dc->dctype == DCTYPE_DIRECT)
5620 MouseSafetyOnDrawEnd(dc->ppdev);
5621
5622 BackgroundLeft = DestRect.right;
5623 }
5624
5625 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5626 DestRect.right = DestRect.left + realglyph->bitmap.width;
5627 DestRect.top = TextTop + yoff - realglyph->top;
5628 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5629
5630 bitSize.cx = realglyph->bitmap.width;
5631 bitSize.cy = realglyph->bitmap.rows;
5632 MaskRect.right = realglyph->bitmap.width;
5633 MaskRect.bottom = realglyph->bitmap.rows;
5634
5635 /* Check if the bitmap has any pixels */
5636 if ((bitSize.cx != 0) && (bitSize.cy != 0))
5637 {
5638 /*
5639 * We should create the bitmap out of the loop at the biggest possible
5640 * glyph size. Then use memset with 0 to clear it and sourcerect to
5641 * limit the work of the transbitblt.
5642 */
5643 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
5644 BMF_8BPP, BMF_TOPDOWN,
5645 realglyph->bitmap.buffer);
5646 if ( !HSourceGlyph )
5647 {
5648 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
5649 // FT_Done_Glyph(realglyph);
5650 bResult = FALSE;
5651 break;
5652 }
5653 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
5654 if ( !SourceGlyphSurf )
5655 {
5656 EngDeleteSurface((HSURF)HSourceGlyph);
5657 DPRINT1("WARNING: EngLockSurface() failed!\n");
5658 bResult = FALSE;
5659 break;
5660 }
5661
5662 /*
5663 * Use the font data as a mask to paint onto the DCs surface using a
5664 * brush.
5665 */
5666 if (lprc && (fuOptions & ETO_CLIPPED) &&
5667 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
5668 {
5669 // We do the check '>=' instead of '>' to possibly save an iteration
5670 // through this loop, since it's breaking after the drawing is done,
5671 // and x is always incremented.
5672 DestRect.right = lprc->right + dc->ptlDCOrig.x;
5673 DoBreak = TRUE;
5674 }
5675 if (lprc && (fuOptions & ETO_CLIPPED) &&
5676 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
5677 {
5678 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
5679 }
5680
5681 if (dc->dctype == DCTYPE_DIRECT)
5682 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5683
5684 if (!IntEngMaskBlt(
5685 SurfObj,
5686 SourceGlyphSurf,
5687 (CLIPOBJ *)&dc->co,
5688 &exloRGB2Dst.xlo,
5689 &exloDst2RGB.xlo,
5690 &DestRect,
5691 (PPOINTL)&MaskRect,
5692 &dc->eboText.BrushObject,
5693 &BrushOrigin))
5694 {
5695 DPRINT1("Failed to MaskBlt a glyph!\n");
5696 }
5697
5698 if (dc->dctype == DCTYPE_DIRECT)
5699 MouseSafetyOnDrawEnd(dc->ppdev) ;
5700
5701 EngUnlockSurface(SourceGlyphSurf);
5702 EngDeleteSurface((HSURF)HSourceGlyph);
5703 }
5704
5705 if (DoBreak)
5706 {
5707 break;
5708 }
5709
5710 if (plf->lfUnderline)
5711 {
5712 int i, position;
5713 if (!face->units_per_EM)
5714 {
5715 position = 0;
5716 }
5717 else
5718 {
5719 position = face->underline_position *
5720 face->size->metrics.y_ppem / face->units_per_EM;
5721 }
5722 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5723 {
5724 EngLineTo(SurfObj,
5725 (CLIPOBJ *)&dc->co,
5726 &dc->eboText.BrushObject,
5727 (TextLeft >> 6),
5728 TextTop + yoff - position + i,
5729 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5730 TextTop + yoff - position + i,
5731 NULL,
5732 ROP2_TO_MIX(R2_COPYPEN));
5733 }
5734 }
5735 if (plf->lfStrikeOut)
5736 {
5737 int i;
5738 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5739 {
5740 EngLineTo(SurfObj,
5741 (CLIPOBJ *)&dc->co,
5742 &dc->eboText.BrushObject,
5743 (TextLeft >> 6),
5744 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5745 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5746 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5747 NULL,
5748 ROP2_TO_MIX(R2_COPYPEN));
5749 }
5750 }
5751
5752 if (NULL == Dx)
5753 {
5754 TextLeft += realglyph->root.advance.x >> 10;
5755 DPRINT("New TextLeft: %I64d\n", TextLeft);
5756 }
5757 else
5758 {
5759 // FIXME this should probably be a matrix transform with TextTop as well.
5760 Scale = pdcattr->mxWorldToDevice.efM11;
5761 if (FLOATOBJ_Equal0(&Scale))
5762 FLOATOBJ_Set1(&Scale);
5763
5764 /* do the shift before multiplying to preserve precision */
5765 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5766 TextLeft += FLOATOBJ_GetLong(&Scale);
5767 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5768 }
5769
5770 if (DxShift)
5771 {
5772 TextTop -= Dx[2 * i + 1] << 6;
5773 }
5774
5775 previous = glyph_index;
5776
5777 if (EmuBold || EmuItalic)
5778 {
5779 FT_Done_Glyph((FT_Glyph)realglyph);
5780 realglyph = NULL;
5781 }
5782 }
5783
5784 if (pdcattr->lTextAlign & TA_UPDATECP) {
5785 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
5786 }
5787
5788 IntUnLockFreeType;
5789
5790 EXLATEOBJ_vCleanup(&exloRGB2Dst);
5791 EXLATEOBJ_vCleanup(&exloDst2RGB);
5792
5793 Cleanup:
5794
5795 DC_vFinishBlit(dc, NULL);
5796
5797 if (TextObj != NULL)
5798 TEXTOBJ_UnlockText(TextObj);
5799
5800 DC_UnlockDc(dc);
5801
5802 return bResult;
5803 }
5804
5805 #define STACK_TEXT_BUFFER_SIZE 100
5806 BOOL
5807 APIENTRY
5808 NtGdiExtTextOutW(
5809 IN HDC hDC,
5810 IN INT XStart,
5811 IN INT YStart,
5812 IN UINT fuOptions,
5813 IN OPTIONAL LPRECT UnsafeRect,
5814 IN LPWSTR UnsafeString,
5815 IN INT Count,
5816 IN OPTIONAL LPINT UnsafeDx,
5817 IN DWORD dwCodePage)
5818 {
5819 BOOL Result = FALSE;
5820 NTSTATUS Status = STATUS_SUCCESS;
5821 RECTL SafeRect;
5822 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
5823 PVOID Buffer = LocalBuffer;
5824 LPCWSTR SafeString = NULL;
5825 LPINT SafeDx = NULL;
5826 ULONG BufSize, StringSize, DxSize = 0;
5827
5828 /* Check if String is valid */
5829 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
5830 {
5831 EngSetLastError(ERROR_INVALID_PARAMETER);
5832 return FALSE;
5833 }
5834
5835 if (Count > 0)
5836 {
5837 /* Calculate buffer size for string and Dx values */
5838 BufSize = StringSize = Count * sizeof(WCHAR);
5839 if (UnsafeDx)
5840 {
5841 /* If ETO_PDY is specified, we have pairs of INTs */
5842 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
5843 BufSize += DxSize;
5844 }
5845
5846 /* Check if our local buffer is large enough */
5847 if (BufSize > STACK_TEXT_BUFFER_SIZE)
5848 {
5849 /* It's not, allocate a temp buffer */
5850 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
5851 if (!Buffer)
5852 {
5853 return FALSE;
5854 }
5855 }
5856
5857 /* Probe and copy user mode data to the buffer */
5858 _SEH2_TRY
5859 {
5860 /* Put the Dx before the String to assure alignment of 4 */
5861 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
5862
5863 /* Probe and copy the string */
5864 ProbeForRead(UnsafeString, StringSize, 1);
5865 memcpy((PVOID)SafeString, UnsafeString, StringSize);
5866
5867 /* If we have Dx values... */
5868 if (UnsafeDx)
5869 {
5870 /* ... probe and copy them */
5871 SafeDx = Buffer;
5872 ProbeForRead(UnsafeDx, DxSize, 1);
5873 memcpy(SafeDx, UnsafeDx, DxSize);
5874 }
5875 }
5876 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5877 {
5878 Status = _SEH2_GetExceptionCode();
5879 }
5880 _SEH2_END
5881 if (!NT_SUCCESS(Status))
5882 {
5883 goto cleanup;
5884 }
5885 }
5886
5887 /* If we have a rect, copy it */
5888 if (UnsafeRect)
5889 {
5890 _SEH2_TRY
5891 {
5892 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
5893 SafeRect = *UnsafeRect;
5894 }
5895 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5896 {
5897 Status = _SEH2_GetExceptionCode();
5898 }
5899 _SEH2_END
5900 if (!NT_SUCCESS(Status))
5901 {
5902 goto cleanup;
5903 }
5904 }
5905
5906 /* Finally call the internal routine */
5907 Result = GreExtTextOutW(hDC,
5908 XStart,
5909 YStart,
5910 fuOptions,
5911 &SafeRect,
5912 SafeString,
5913 Count,
5914 SafeDx,
5915 dwCodePage);
5916
5917 cleanup:
5918 /* If we allocated a buffer, free it */
5919 if (Buffer != LocalBuffer)
5920 {
5921 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
5922 }
5923
5924 return Result;
5925 }
5926
5927
5928 /*
5929 * @implemented
5930 */
5931 BOOL
5932 APIENTRY
5933 NtGdiGetCharABCWidthsW(
5934 IN HDC hDC,
5935 IN UINT FirstChar,
5936 IN ULONG Count,
5937 IN OPTIONAL PWCHAR UnSafepwch,
5938 IN FLONG fl,
5939 OUT PVOID Buffer)
5940 {
5941 LPABC SafeBuff;
5942 LPABCFLOAT SafeBuffF = NULL;
5943 PDC dc;
5944 PDC_ATTR pdcattr;
5945 PTEXTOBJ TextObj;
5946 PFONTGDI FontGDI;
5947 FT_Face face;
5948 FT_CharMap charmap, found = NULL;
5949 UINT i, glyph_index, BufferSize;
5950 HFONT hFont = 0;
5951 NTSTATUS Status = STATUS_SUCCESS;
5952 PMATRIX pmxWorldToDevice;
5953 PWCHAR Safepwch = NULL;
5954 LOGFONTW *plf;
5955
5956 if (!Buffer)
5957 {
5958 EngSetLastError(ERROR_INVALID_PARAMETER);
5959 return FALSE;
5960 }
5961
5962 if (UnSafepwch)
5963 {
5964 UINT pwchSize = Count * sizeof(WCHAR);
5965 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
5966
5967 if(!Safepwch)
5968 {
5969 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5970 return FALSE;
5971 }
5972
5973 _SEH2_TRY
5974 {
5975 ProbeForRead(UnSafepwch, pwchSize, 1);
5976 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
5977 }
5978 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5979 {
5980 Status = _SEH2_GetExceptionCode();
5981 }
5982 _SEH2_END;
5983 }
5984
5985 if (!NT_SUCCESS(Status))
5986 {
5987 if(Safepwch)
5988 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
5989
5990 EngSetLastError(Status);
5991 return FALSE;
5992 }
5993
5994 BufferSize = Count * sizeof(ABC); // Same size!
5995 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
5996 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
5997 if (SafeBuff == NULL)
5998 {
5999
6000 if(Safepwch)
6001 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6002
6003 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6004 return FALSE;
6005 }
6006
6007 dc = DC_LockDc(hDC);
6008 if (dc == NULL)
6009 {
6010 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6011
6012 if(Safepwch)
6013 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6014
6015 EngSetLastError(ERROR_INVALID_HANDLE);
6016 return FALSE;
6017 }
6018 pdcattr = dc->pdcattr;
6019 hFont = pdcattr->hlfntNew;
6020 TextObj = RealizeFontInit(hFont);
6021
6022 /* Get the DC's world-to-device transformation matrix */
6023 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6024 DC_UnlockDc(dc);
6025
6026 if (TextObj == NULL)
6027 {
6028 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6029
6030 if(Safepwch)
6031 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6032
6033 EngSetLastError(ERROR_INVALID_HANDLE);
6034 return FALSE;
6035 }
6036
6037 FontGDI = ObjToGDI(TextObj->Font, FONT);
6038
6039 face = FontGDI->SharedFace->Face;
6040 if (face->charmap == NULL)
6041 {
6042 for (i = 0; i < (UINT)face->num_charmaps; i++)
6043 {
6044 charmap = face->charmaps[i];
6045 if (charmap->encoding != 0)
6046 {
6047 found = charmap;
6048 break;
6049 }
6050 }
6051
6052 if (!found)
6053 {
6054 DPRINT1("WARNING: Could not find desired charmap!\n");
6055 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6056
6057 if(Safepwch)
6058 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6059
6060 EngSetLastError(ERROR_INVALID_HANDLE);
6061 return FALSE;
6062 }
6063
6064 IntLockFreeType;
6065 FT_Set_Charmap(face, found);
6066 IntUnLockFreeType;
6067 }
6068
6069 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6070 IntLockFreeType;
6071 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
6072 FtSetCoordinateTransform(face, pmxWorldToDevice);
6073
6074 for (i = FirstChar; i < FirstChar+Count; i++)
6075 {
6076 int adv, lsb, bbx, left, right;
6077
6078 if (Safepwch)
6079 {
6080 if (fl & GCABCW_INDICES)
6081 glyph_index = Safepwch[i - FirstChar];
6082 else
6083 glyph_index = FT_Get_Char_Index(face, Safepwch[i - FirstChar]);
6084 }
6085 else
6086 {
6087 if (fl & GCABCW_INDICES)
6088 glyph_index = i;
6089 else
6090 glyph_index = FT_Get_Char_Index(face, i);
6091 }
6092 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6093
6094 left = (INT)face->glyph->metrics.horiBearingX & -64;
6095 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
6096 adv = (face->glyph->advance.x + 32) >> 6;
6097
6098 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
6099 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
6100
6101 lsb = left >> 6;
6102 bbx = (right - left) >> 6;
6103 /*
6104 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
6105 */
6106 if (!fl)
6107 {
6108 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
6109 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
6110 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
6111 }
6112 else
6113 {
6114 SafeBuff[i - FirstChar].abcA = lsb;
6115 SafeBuff[i - FirstChar].abcB = bbx;
6116 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
6117 }
6118 }
6119 IntUnLockFreeType;
6120 TEXTOBJ_UnlockText(TextObj);
6121 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6122
6123 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6124
6125 if(Safepwch)
6126 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6127
6128 if (! NT_SUCCESS(Status))
6129 {
6130 SetLastNtError(Status);
6131 return FALSE;
6132 }
6133
6134 DPRINT("NtGdiGetCharABCWidths Worked!\n");
6135 return TRUE;
6136 }
6137
6138 /*
6139 * @implemented
6140 */
6141 BOOL
6142 APIENTRY
6143 NtGdiGetCharWidthW(
6144 IN HDC hDC,
6145 IN UINT FirstChar,
6146 IN UINT Count,
6147 IN OPTIONAL PWCHAR UnSafepwc,
6148 IN FLONG fl,
6149 OUT PVOID Buffer)
6150 {
6151 NTSTATUS Status = STATUS_SUCCESS;
6152 LPINT SafeBuff;
6153 PFLOAT SafeBuffF = NULL;
6154 PDC dc;
6155 PDC_ATTR pdcattr;
6156 PTEXTOBJ TextObj;
6157 PFONTGDI FontGDI;
6158 FT_Face face;
6159 FT_CharMap charmap, found = NULL;
6160 UINT i, glyph_index, BufferSize;
6161 HFONT hFont = 0;
6162 PMATRIX pmxWorldToDevice;
6163 PWCHAR Safepwc = NULL;
6164 LOGFONTW *plf;
6165
6166 if (UnSafepwc)
6167 {
6168 UINT pwcSize = Count * sizeof(WCHAR);
6169 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6170
6171 if(!Safepwc)
6172 {
6173 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6174 return FALSE;
6175 }
6176 _SEH2_TRY
6177 {
6178 ProbeForRead(UnSafepwc, pwcSize, 1);
6179 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6180 }
6181 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6182 {
6183 Status = _SEH2_GetExceptionCode();
6184 }
6185 _SEH2_END;
6186 }
6187
6188 if (!NT_SUCCESS(Status))
6189 {
6190 EngSetLastError(Status);
6191 return FALSE;
6192 }
6193
6194 BufferSize = Count * sizeof(INT); // Same size!
6195 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6196 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
6197 if (SafeBuff == NULL)
6198 {
6199 if(Safepwc)
6200 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6201
6202 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6203 return FALSE;
6204 }
6205
6206 dc = DC_LockDc(hDC);
6207 if (dc == NULL)
6208 {
6209 if(Safepwc)
6210 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6211
6212 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6213 EngSetLastError(ERROR_INVALID_HANDLE);
6214 return FALSE;
6215 }
6216 pdcattr = dc->pdcattr;
6217 hFont = pdcattr->hlfntNew;
6218 TextObj = RealizeFontInit(hFont);
6219 /* Get the DC's world-to-device transformation matrix */
6220 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6221 DC_UnlockDc(dc);
6222
6223 if (TextObj == NULL)
6224 {
6225 if(Safepwc)
6226 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6227
6228 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6229 EngSetLastError(ERROR_INVALID_HANDLE);
6230 return FALSE;
6231 }
6232
6233 FontGDI = ObjToGDI(TextObj->Font, FONT);
6234
6235 face = FontGDI->SharedFace->Face;
6236 if (face->charmap == NULL)
6237 {
6238 for (i = 0; i < (UINT)face->num_charmaps; i++)
6239 {
6240 charmap = face->charmaps[i];
6241 if (charmap->encoding != 0)
6242 {
6243 found = charmap;
6244 break;
6245 }
6246 }
6247
6248 if (!found)
6249 {
6250 DPRINT1("WARNING: Could not find desired charmap!\n");
6251
6252 if(Safepwc)
6253 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6254
6255 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6256 EngSetLastError(ERROR_INVALID_HANDLE);
6257 return FALSE;
6258 }
6259
6260 IntLockFreeType;
6261 FT_Set_Charmap(face, found);
6262 IntUnLockFreeType;
6263 }
6264
6265 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6266 IntLockFreeType;
6267 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
6268 FtSetCoordinateTransform(face, pmxWorldToDevice);
6269
6270 for (i = FirstChar; i < FirstChar+Count; i++)
6271 {
6272 if (Safepwc)
6273 {
6274 if (fl & GCW_INDICES)
6275 glyph_index = Safepwc[i - FirstChar];
6276 else
6277 glyph_index = FT_Get_Char_Index(face, Safepwc[i - FirstChar]);
6278 }
6279 else
6280 {
6281 if (fl & GCW_INDICES)
6282 glyph_index = i;
6283 else
6284 glyph_index = FT_Get_Char_Index(face, i);
6285 }
6286 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6287 if (!fl)
6288 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
6289 else
6290 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
6291 }
6292 IntUnLockFreeType;
6293 TEXTOBJ_UnlockText(TextObj);
6294 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6295
6296 if(Safepwc)
6297 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6298
6299 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6300 return TRUE;
6301 }
6302
6303
6304 /*
6305 * @implemented
6306 */
6307 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
6308 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
6309 // NOTE: See also GreGetGlyphIndicesW.
6310 __kernel_entry
6311 W32KAPI
6312 DWORD
6313 APIENTRY
6314 NtGdiGetGlyphIndicesW(
6315 _In_ HDC hdc,
6316 _In_reads_opt_(cwc) LPCWSTR pwc,
6317 _In_ INT cwc,
6318 _Out_writes_opt_(cwc) LPWORD pgi,
6319 _In_ DWORD iMode)
6320 {
6321 PDC dc;
6322 PDC_ATTR pdcattr;
6323 PTEXTOBJ TextObj;
6324 PFONTGDI FontGDI;
6325 HFONT hFont = NULL;
6326 NTSTATUS Status = STATUS_SUCCESS;
6327 OUTLINETEXTMETRICW *potm;
6328 INT i;
6329 WCHAR DefChar = 0xffff;
6330 PWSTR Buffer = NULL;
6331 ULONG Size, pwcSize;
6332 PWSTR Safepwc = NULL;
6333 LPCWSTR UnSafepwc = pwc;
6334 LPWORD UnSafepgi = pgi;
6335
6336 /* Check for integer overflow */
6337 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN
6338 return GDI_ERROR;
6339
6340 if (!UnSafepwc && !UnSafepgi)
6341 return cwc;
6342
6343 if (!UnSafepwc || !UnSafepgi)
6344 {
6345 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
6346 return GDI_ERROR;
6347 }
6348
6349 // TODO: Special undocumented case!
6350 if (!pwc && !pgi && (cwc == 0))
6351 {
6352 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n");
6353 return 0;
6354 }
6355
6356 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825
6357 if (cwc == 0)
6358 {
6359 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n");
6360 return GDI_ERROR;
6361 }
6362
6363 dc = DC_LockDc(hdc);
6364 if (!dc)
6365 {
6366 return GDI_ERROR;
6367 }
6368 pdcattr = dc->pdcattr;
6369 hFont = pdcattr->hlfntNew;
6370 TextObj = RealizeFontInit(hFont);
6371 DC_UnlockDc(dc);
6372 if (!TextObj)
6373 {
6374 return GDI_ERROR;
6375 }
6376
6377 FontGDI = ObjToGDI(TextObj->Font, FONT);
6378 TEXTOBJ_UnlockText(TextObj);
6379
6380 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
6381 if (!Buffer)
6382 {
6383 return GDI_ERROR;
6384 }
6385
6386 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
6387 {
6388 DefChar = 0xffff;
6389 }
6390 else
6391 {
6392 FT_Face Face = FontGDI->SharedFace->Face;
6393 if (FT_IS_SFNT(Face))
6394 {
6395 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
6396 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(Face, pOS2->usDefaultChar) : 0);
6397 }
6398 else
6399 {
6400 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
6401 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
6402 if (!potm)
6403 {
6404 cwc = GDI_ERROR;
6405 goto ErrorRet;
6406 }
6407 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
6408 if (Size)
6409 DefChar = potm->otmTextMetrics.tmDefaultChar;
6410 ExFreePoolWithTag(potm, GDITAG_TEXT);
6411 }
6412 }
6413
6414 pwcSize = cwc * sizeof(WCHAR);
6415 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6416
6417 if (!Safepwc)
6418 {
6419 Status = STATUS_NO_MEMORY;
6420 goto ErrorRet;
6421 }
6422
6423 _SEH2_TRY
6424 {
6425 ProbeForRead(UnSafepwc, pwcSize, 1);
6426 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6427 }
6428 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6429 {
6430 Status = _SEH2_GetExceptionCode();
6431 }
6432 _SEH2_END;
6433
6434 if (!NT_SUCCESS(Status)) goto ErrorRet;
6435
6436 IntLockFreeType;
6437
6438 for (i = 0; i < cwc; i++)
6439 {
6440 Buffer[i] = FT_Get_Char_Index(FontGDI->SharedFace->Face, Safepwc[i]);
6441 if (Buffer[i] == 0)
6442 {
6443 Buffer[i] = DefChar;
6444 }
6445 }
6446
6447 IntUnLockFreeType;
6448
6449 _SEH2_TRY
6450 {
6451 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
6452 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
6453 }
6454 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6455 {
6456 Status = _SEH2_GetExceptionCode();
6457 }
6458 _SEH2_END;
6459
6460 ErrorRet:
6461 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6462 if (Safepwc != NULL)
6463 {
6464 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6465 }
6466 if (NT_SUCCESS(Status)) return cwc;
6467 return GDI_ERROR;
6468 }
6469
6470 /* EOF */