485f09774fdb67d7a24e717b444a0bf0b80c0760
[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 /* NOTE: This function locks the screen DC, so it must never be called
5115 with a DC already locked */
5116 Render = IntIsFontRenderingEnabled();
5117
5118 // TODO: Write test-cases to exactly match real Windows in different
5119 // bad parameters (e.g. does Windows check the DC or the RECT first?).
5120 dc = DC_LockDc(hDC);
5121 if (!dc)
5122 {
5123 EngSetLastError(ERROR_INVALID_HANDLE);
5124 return FALSE;
5125 }
5126
5127 if (PATH_IsPathOpen(dc->dclevel))
5128 {
5129 bResult = PATH_ExtTextOut(dc,
5130 XStart,
5131 YStart,
5132 fuOptions,
5133 (const RECTL *)lprc,
5134 String,
5135 Count,
5136 (const INT *)Dx);
5137 DC_UnlockDc(dc);
5138 return bResult;
5139 }
5140
5141 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
5142
5143 if (!dc->dclevel.pSurface)
5144 {
5145 /* Memory DC with no surface selected */
5146 bResult = FALSE; // TRUE?
5147 goto Cleanup;
5148 }
5149
5150 pdcattr = dc->pdcattr;
5151
5152 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
5153 {
5154 IntLPtoDP(dc, (POINT *)lprc, 2);
5155 }
5156
5157 if (pdcattr->lTextAlign & TA_UPDATECP)
5158 {
5159 Start.x = pdcattr->ptlCurrent.x;
5160 Start.y = pdcattr->ptlCurrent.y;
5161 } else {
5162 Start.x = XStart;
5163 Start.y = YStart;
5164 }
5165
5166 IntLPtoDP(dc, &Start, 1);
5167 RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
5168 YStart = Start.y + dc->ptlDCOrig.y;
5169
5170 SourcePoint.x = 0;
5171 SourcePoint.y = 0;
5172 MaskRect.left = 0;
5173 MaskRect.top = 0;
5174 BrushOrigin.x = 0;
5175 BrushOrigin.y = 0;
5176
5177 if ((fuOptions & ETO_OPAQUE) && lprc)
5178 {
5179 DestRect.left = lprc->left;
5180 DestRect.top = lprc->top;
5181 DestRect.right = lprc->right;
5182 DestRect.bottom = lprc->bottom;
5183
5184 DestRect.left += dc->ptlDCOrig.x;
5185 DestRect.top += dc->ptlDCOrig.y;
5186 DestRect.right += dc->ptlDCOrig.x;
5187 DestRect.bottom += dc->ptlDCOrig.y;
5188
5189 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5190 {
5191 IntUpdateBoundsRect(dc, &DestRect);
5192 }
5193
5194 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5195 DC_vUpdateBackgroundBrush(dc);
5196 if (dc->dctype == DCTYPE_DIRECT)
5197 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5198
5199 psurf = dc->dclevel.pSurface;
5200 IntEngBitBlt(
5201 &psurf->SurfObj,
5202 NULL,
5203 NULL,
5204 (CLIPOBJ *)&dc->co,
5205 NULL,
5206 &DestRect,
5207 &SourcePoint,
5208 &SourcePoint,
5209 &dc->eboBackground.BrushObject,
5210 &BrushOrigin,
5211 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5212
5213 if (dc->dctype == DCTYPE_DIRECT)
5214 MouseSafetyOnDrawEnd(dc->ppdev);
5215
5216 fuOptions &= ~ETO_OPAQUE;
5217 }
5218 else
5219 {
5220 if (pdcattr->jBkMode == OPAQUE)
5221 {
5222 fuOptions |= ETO_OPAQUE;
5223 }
5224 }
5225
5226 TextObj = RealizeFontInit(pdcattr->hlfntNew);
5227 if (TextObj == NULL)
5228 {
5229 bResult = FALSE;
5230 goto Cleanup;
5231 }
5232
5233 FontObj = TextObj->Font;
5234 ASSERT(FontObj);
5235 FontGDI = ObjToGDI(FontObj, FONT);
5236 ASSERT(FontGDI);
5237
5238 IntLockFreeType;
5239 face = FontGDI->SharedFace->Face;
5240
5241 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5242 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
5243 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
5244
5245 if (Render)
5246 RenderMode = IntGetFontRenderMode(plf);
5247 else
5248 RenderMode = FT_RENDER_MODE_MONO;
5249
5250 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
5251 {
5252 IntUnLockFreeType;
5253 bResult = FALSE;
5254 goto Cleanup;
5255 }
5256
5257 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
5258 {
5259 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
5260 FtSetCoordinateTransform(face, pmxWorldToDevice);
5261
5262 fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
5263 fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
5264 }
5265 else
5266 {
5267 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
5268 FtSetCoordinateTransform(face, pmxWorldToDevice);
5269
5270 fixAscender = face->size->metrics.ascender;
5271 fixDescender = face->size->metrics.descender;
5272 }
5273
5274 /*
5275 * Process the vertical alignment and determine the yoff.
5276 */
5277
5278 if (pdcattr->lTextAlign & TA_BASELINE)
5279 yoff = 0;
5280 else if (pdcattr->lTextAlign & TA_BOTTOM)
5281 yoff = -fixDescender >> 6;
5282 else /* TA_TOP */
5283 yoff = fixAscender >> 6;
5284
5285 use_kerning = FT_HAS_KERNING(face);
5286 previous = 0;
5287
5288 /*
5289 * Process the horizontal alignment and modify XStart accordingly.
5290 */
5291 DxShift = fuOptions & ETO_PDY ? 1 : 0;
5292 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
5293 {
5294 ULONGLONG TextWidth = 0;
5295 LPCWSTR TempText = String;
5296 int iStart;
5297
5298 /*
5299 * Calculate width of the text.
5300 */
5301
5302 if (NULL != Dx)
5303 {
5304 iStart = Count < 2 ? 0 : Count - 2;
5305 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
5306 }
5307 else
5308 {
5309 iStart = 0;
5310 }
5311 TempText = String + iStart;
5312
5313 for (i = iStart; i < Count; i++)
5314 {
5315 if (fuOptions & ETO_GLYPH_INDEX)
5316 glyph_index = *TempText;
5317 else
5318 glyph_index = FT_Get_Char_Index(face, *TempText);
5319
5320 if (EmuBold || EmuItalic)
5321 realglyph = NULL;
5322 else
5323 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
5324 plf->lfHeight, pmxWorldToDevice);
5325 if (!realglyph)
5326 {
5327 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5328 if (error)
5329 {
5330 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
5331 }
5332
5333 glyph = face->glyph;
5334 if (EmuBold || EmuItalic)
5335 {
5336 if (EmuBold)
5337 FT_GlyphSlot_Embolden(glyph);
5338 if (EmuItalic)
5339 FT_GlyphSlot_Oblique(glyph);
5340 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5341 }
5342 else
5343 {
5344 realglyph = ftGdiGlyphCacheSet(face,
5345 glyph_index,
5346 plf->lfHeight,
5347 pmxWorldToDevice,
5348 glyph,
5349 RenderMode);
5350 }
5351 if (!realglyph)
5352 {
5353 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5354 IntUnLockFreeType;
5355 goto Cleanup;
5356 }
5357
5358 }
5359 /* Retrieve kerning distance */
5360 if (use_kerning && previous && glyph_index)
5361 {
5362 FT_Vector delta;
5363 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5364 TextWidth += delta.x;
5365 }
5366
5367 TextWidth += realglyph->root.advance.x >> 10;
5368
5369 if (EmuBold || EmuItalic)
5370 {
5371 FT_Done_Glyph((FT_Glyph)realglyph);
5372 realglyph = NULL;
5373 }
5374
5375 previous = glyph_index;
5376 TempText++;
5377 }
5378
5379 previous = 0;
5380
5381 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
5382 {
5383 RealXStart -= TextWidth / 2;
5384 }
5385 else
5386 {
5387 RealXStart -= TextWidth;
5388 }
5389 }
5390
5391 psurf = dc->dclevel.pSurface;
5392 SurfObj = &psurf->SurfObj ;
5393
5394 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
5395 DC_vUpdateBackgroundBrush(dc) ;
5396
5397 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
5398 DC_vUpdateTextBrush(dc) ;
5399
5400 if (!face->units_per_EM)
5401 {
5402 thickness = 1;
5403 }
5404 else
5405 {
5406 thickness = face->underline_thickness *
5407 face->size->metrics.y_ppem / face->units_per_EM;
5408 if (thickness <= 0)
5409 thickness = 1;
5410 }
5411
5412 if ((fuOptions & ETO_OPAQUE) && plf->lfItalic)
5413 {
5414 /* Draw background */
5415 TextLeft = RealXStart;
5416 TextTop = YStart;
5417 BackgroundLeft = (RealXStart + 32) >> 6;
5418 for (i = 0; i < Count; ++i)
5419 {
5420 if (fuOptions & ETO_GLYPH_INDEX)
5421 glyph_index = String[i];
5422 else
5423 glyph_index = FT_Get_Char_Index(face, String[i]);
5424
5425 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5426 if (error)
5427 {
5428 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5429 IntUnLockFreeType;
5430 goto Cleanup;
5431 }
5432
5433 glyph = face->glyph;
5434 if (EmuBold)
5435 FT_GlyphSlot_Embolden(glyph);
5436 if (EmuItalic)
5437 FT_GlyphSlot_Oblique(glyph);
5438 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5439 if (!realglyph)
5440 {
5441 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5442 IntUnLockFreeType;
5443 goto Cleanup;
5444 }
5445
5446 /* retrieve kerning distance and move pen position */
5447 if (use_kerning && previous && glyph_index && NULL == Dx)
5448 {
5449 FT_Vector delta;
5450 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5451 TextLeft += delta.x;
5452 }
5453 DPRINT("TextLeft: %I64d\n", TextLeft);
5454 DPRINT("TextTop: %lu\n", TextTop);
5455 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5456
5457 DestRect.left = BackgroundLeft;
5458 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5459 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5460 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5461 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5462 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5463 {
5464 IntUpdateBoundsRect(dc, &DestRect);
5465 }
5466 IntEngBitBlt(
5467 &psurf->SurfObj,
5468 NULL,
5469 NULL,
5470 (CLIPOBJ *)&dc->co,
5471 NULL,
5472 &DestRect,
5473 &SourcePoint,
5474 &SourcePoint,
5475 &dc->eboBackground.BrushObject,
5476 &BrushOrigin,
5477 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5478 MouseSafetyOnDrawEnd(dc->ppdev);
5479 BackgroundLeft = DestRect.right;
5480
5481 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5482 DestRect.right = DestRect.left + realglyph->bitmap.width;
5483 DestRect.top = TextTop + yoff - realglyph->top;
5484 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5485
5486 bitSize.cx = realglyph->bitmap.width;
5487 bitSize.cy = realglyph->bitmap.rows;
5488 MaskRect.right = realglyph->bitmap.width;
5489 MaskRect.bottom = realglyph->bitmap.rows;
5490
5491 if (NULL == Dx)
5492 {
5493 TextLeft += realglyph->root.advance.x >> 10;
5494 DPRINT("New TextLeft: %I64d\n", TextLeft);
5495 }
5496 else
5497 {
5498 // FIXME this should probably be a matrix transform with TextTop as well.
5499 Scale = pdcattr->mxWorldToDevice.efM11;
5500 if (FLOATOBJ_Equal0(&Scale))
5501 FLOATOBJ_Set1(&Scale);
5502
5503 /* do the shift before multiplying to preserve precision */
5504 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5505 TextLeft += FLOATOBJ_GetLong(&Scale);
5506 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5507 }
5508
5509 if (DxShift)
5510 {
5511 TextTop -= Dx[2 * i + 1] << 6;
5512 }
5513
5514 previous = glyph_index;
5515
5516 if (EmuBold || EmuItalic)
5517 {
5518 FT_Done_Glyph((FT_Glyph)realglyph);
5519 realglyph = NULL;
5520 }
5521 }
5522 }
5523
5524 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
5525 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
5526
5527 /* Assume success */
5528 bResult = TRUE;
5529
5530 /*
5531 * The main rendering loop.
5532 */
5533 TextLeft = RealXStart;
5534 TextTop = YStart;
5535 BackgroundLeft = (RealXStart + 32) >> 6;
5536 for (i = 0; i < Count; ++i)
5537 {
5538 if (fuOptions & ETO_GLYPH_INDEX)
5539 glyph_index = String[i];
5540 else
5541 glyph_index = FT_Get_Char_Index(face, String[i]);
5542
5543 if (EmuBold || EmuItalic)
5544 realglyph = NULL;
5545 else
5546 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
5547 plf->lfHeight, pmxWorldToDevice);
5548 if (!realglyph)
5549 {
5550 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5551 if (error)
5552 {
5553 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5554 bResult = FALSE;
5555 break;
5556 }
5557
5558 glyph = face->glyph;
5559 if (EmuBold || EmuItalic)
5560 {
5561 if (EmuBold)
5562 FT_GlyphSlot_Embolden(glyph);
5563 if (EmuItalic)
5564 FT_GlyphSlot_Oblique(glyph);
5565 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5566 }
5567 else
5568 {
5569 realglyph = ftGdiGlyphCacheSet(face,
5570 glyph_index,
5571 plf->lfHeight,
5572 pmxWorldToDevice,
5573 glyph,
5574 RenderMode);
5575 }
5576 if (!realglyph)
5577 {
5578 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5579 bResult = FALSE;
5580 break;
5581 }
5582 }
5583
5584 /* retrieve kerning distance and move pen position */
5585 if (use_kerning && previous && glyph_index && NULL == Dx)
5586 {
5587 FT_Vector delta;
5588 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5589 TextLeft += delta.x;
5590 }
5591 DPRINT("TextLeft: %I64d\n", TextLeft);
5592 DPRINT("TextTop: %lu\n", TextTop);
5593 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5594
5595 if ((fuOptions & ETO_OPAQUE) && !plf->lfItalic)
5596 {
5597 DestRect.left = BackgroundLeft;
5598 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5599 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5600 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5601
5602 if (dc->dctype == DCTYPE_DIRECT)
5603 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5604
5605 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5606 {
5607 IntUpdateBoundsRect(dc, &DestRect);
5608 }
5609 IntEngBitBlt(
5610 &psurf->SurfObj,
5611 NULL,
5612 NULL,
5613 (CLIPOBJ *)&dc->co,
5614 NULL,
5615 &DestRect,
5616 &SourcePoint,
5617 &SourcePoint,
5618 &dc->eboBackground.BrushObject,
5619 &BrushOrigin,
5620 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5621
5622 if (dc->dctype == DCTYPE_DIRECT)
5623 MouseSafetyOnDrawEnd(dc->ppdev);
5624
5625 BackgroundLeft = DestRect.right;
5626 }
5627
5628 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5629 DestRect.right = DestRect.left + realglyph->bitmap.width;
5630 DestRect.top = TextTop + yoff - realglyph->top;
5631 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5632
5633 bitSize.cx = realglyph->bitmap.width;
5634 bitSize.cy = realglyph->bitmap.rows;
5635 MaskRect.right = realglyph->bitmap.width;
5636 MaskRect.bottom = realglyph->bitmap.rows;
5637
5638 /* Check if the bitmap has any pixels */
5639 if ((bitSize.cx != 0) && (bitSize.cy != 0))
5640 {
5641 /*
5642 * We should create the bitmap out of the loop at the biggest possible
5643 * glyph size. Then use memset with 0 to clear it and sourcerect to
5644 * limit the work of the transbitblt.
5645 */
5646 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
5647 BMF_8BPP, BMF_TOPDOWN,
5648 realglyph->bitmap.buffer);
5649 if ( !HSourceGlyph )
5650 {
5651 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
5652 // FT_Done_Glyph(realglyph);
5653 bResult = FALSE;
5654 break;
5655 }
5656 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
5657 if ( !SourceGlyphSurf )
5658 {
5659 EngDeleteSurface((HSURF)HSourceGlyph);
5660 DPRINT1("WARNING: EngLockSurface() failed!\n");
5661 bResult = FALSE;
5662 break;
5663 }
5664
5665 /*
5666 * Use the font data as a mask to paint onto the DCs surface using a
5667 * brush.
5668 */
5669 if (lprc && (fuOptions & ETO_CLIPPED) &&
5670 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
5671 {
5672 // We do the check '>=' instead of '>' to possibly save an iteration
5673 // through this loop, since it's breaking after the drawing is done,
5674 // and x is always incremented.
5675 DestRect.right = lprc->right + dc->ptlDCOrig.x;
5676 DoBreak = TRUE;
5677 }
5678 if (lprc && (fuOptions & ETO_CLIPPED) &&
5679 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
5680 {
5681 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
5682 }
5683
5684 if (dc->dctype == DCTYPE_DIRECT)
5685 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5686
5687 if (!IntEngMaskBlt(
5688 SurfObj,
5689 SourceGlyphSurf,
5690 (CLIPOBJ *)&dc->co,
5691 &exloRGB2Dst.xlo,
5692 &exloDst2RGB.xlo,
5693 &DestRect,
5694 (PPOINTL)&MaskRect,
5695 &dc->eboText.BrushObject,
5696 &BrushOrigin))
5697 {
5698 DPRINT1("Failed to MaskBlt a glyph!\n");
5699 }
5700
5701 if (dc->dctype == DCTYPE_DIRECT)
5702 MouseSafetyOnDrawEnd(dc->ppdev) ;
5703
5704 EngUnlockSurface(SourceGlyphSurf);
5705 EngDeleteSurface((HSURF)HSourceGlyph);
5706 }
5707
5708 if (DoBreak)
5709 {
5710 break;
5711 }
5712
5713 if (plf->lfUnderline)
5714 {
5715 int i, position;
5716 if (!face->units_per_EM)
5717 {
5718 position = 0;
5719 }
5720 else
5721 {
5722 position = face->underline_position *
5723 face->size->metrics.y_ppem / face->units_per_EM;
5724 }
5725 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5726 {
5727 EngLineTo(SurfObj,
5728 (CLIPOBJ *)&dc->co,
5729 &dc->eboText.BrushObject,
5730 (TextLeft >> 6),
5731 TextTop + yoff - position + i,
5732 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5733 TextTop + yoff - position + i,
5734 NULL,
5735 ROP2_TO_MIX(R2_COPYPEN));
5736 }
5737 }
5738 if (plf->lfStrikeOut)
5739 {
5740 int i;
5741 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5742 {
5743 EngLineTo(SurfObj,
5744 (CLIPOBJ *)&dc->co,
5745 &dc->eboText.BrushObject,
5746 (TextLeft >> 6),
5747 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5748 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5749 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5750 NULL,
5751 ROP2_TO_MIX(R2_COPYPEN));
5752 }
5753 }
5754
5755 if (NULL == Dx)
5756 {
5757 TextLeft += realglyph->root.advance.x >> 10;
5758 DPRINT("New TextLeft: %I64d\n", TextLeft);
5759 }
5760 else
5761 {
5762 // FIXME this should probably be a matrix transform with TextTop as well.
5763 Scale = pdcattr->mxWorldToDevice.efM11;
5764 if (FLOATOBJ_Equal0(&Scale))
5765 FLOATOBJ_Set1(&Scale);
5766
5767 /* do the shift before multiplying to preserve precision */
5768 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5769 TextLeft += FLOATOBJ_GetLong(&Scale);
5770 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5771 }
5772
5773 if (DxShift)
5774 {
5775 TextTop -= Dx[2 * i + 1] << 6;
5776 }
5777
5778 previous = glyph_index;
5779
5780 if (EmuBold || EmuItalic)
5781 {
5782 FT_Done_Glyph((FT_Glyph)realglyph);
5783 realglyph = NULL;
5784 }
5785 }
5786
5787 if (pdcattr->lTextAlign & TA_UPDATECP) {
5788 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
5789 }
5790
5791 IntUnLockFreeType;
5792
5793 EXLATEOBJ_vCleanup(&exloRGB2Dst);
5794 EXLATEOBJ_vCleanup(&exloDst2RGB);
5795
5796 Cleanup:
5797
5798 DC_vFinishBlit(dc, NULL);
5799
5800 if (TextObj != NULL)
5801 TEXTOBJ_UnlockText(TextObj);
5802
5803 DC_UnlockDc(dc);
5804
5805 return bResult;
5806 }
5807
5808 #define STACK_TEXT_BUFFER_SIZE 100
5809 BOOL
5810 APIENTRY
5811 NtGdiExtTextOutW(
5812 IN HDC hDC,
5813 IN INT XStart,
5814 IN INT YStart,
5815 IN UINT fuOptions,
5816 IN OPTIONAL LPRECT UnsafeRect,
5817 IN LPWSTR UnsafeString,
5818 IN INT Count,
5819 IN OPTIONAL LPINT UnsafeDx,
5820 IN DWORD dwCodePage)
5821 {
5822 BOOL Result = FALSE;
5823 NTSTATUS Status = STATUS_SUCCESS;
5824 RECTL SafeRect;
5825 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
5826 PVOID Buffer = LocalBuffer;
5827 LPCWSTR SafeString = NULL;
5828 LPINT SafeDx = NULL;
5829 ULONG BufSize, StringSize, DxSize = 0;
5830
5831 /* Check if String is valid */
5832 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
5833 {
5834 EngSetLastError(ERROR_INVALID_PARAMETER);
5835 return FALSE;
5836 }
5837
5838 if (Count > 0)
5839 {
5840 /* Calculate buffer size for string and Dx values */
5841 BufSize = StringSize = Count * sizeof(WCHAR);
5842 if (UnsafeDx)
5843 {
5844 /* If ETO_PDY is specified, we have pairs of INTs */
5845 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
5846 BufSize += DxSize;
5847 }
5848
5849 /* Check if our local buffer is large enough */
5850 if (BufSize > STACK_TEXT_BUFFER_SIZE)
5851 {
5852 /* It's not, allocate a temp buffer */
5853 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
5854 if (!Buffer)
5855 {
5856 return FALSE;
5857 }
5858 }
5859
5860 /* Probe and copy user mode data to the buffer */
5861 _SEH2_TRY
5862 {
5863 /* Put the Dx before the String to assure alignment of 4 */
5864 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
5865
5866 /* Probe and copy the string */
5867 ProbeForRead(UnsafeString, StringSize, 1);
5868 memcpy((PVOID)SafeString, UnsafeString, StringSize);
5869
5870 /* If we have Dx values... */
5871 if (UnsafeDx)
5872 {
5873 /* ... probe and copy them */
5874 SafeDx = Buffer;
5875 ProbeForRead(UnsafeDx, DxSize, 1);
5876 memcpy(SafeDx, UnsafeDx, DxSize);
5877 }
5878 }
5879 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5880 {
5881 Status = _SEH2_GetExceptionCode();
5882 }
5883 _SEH2_END
5884 if (!NT_SUCCESS(Status))
5885 {
5886 goto cleanup;
5887 }
5888 }
5889
5890 /* If we have a rect, copy it */
5891 if (UnsafeRect)
5892 {
5893 _SEH2_TRY
5894 {
5895 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
5896 SafeRect = *UnsafeRect;
5897 }
5898 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5899 {
5900 Status = _SEH2_GetExceptionCode();
5901 }
5902 _SEH2_END
5903 if (!NT_SUCCESS(Status))
5904 {
5905 goto cleanup;
5906 }
5907 }
5908
5909 /* Finally call the internal routine */
5910 Result = GreExtTextOutW(hDC,
5911 XStart,
5912 YStart,
5913 fuOptions,
5914 &SafeRect,
5915 SafeString,
5916 Count,
5917 SafeDx,
5918 dwCodePage);
5919
5920 cleanup:
5921 /* If we allocated a buffer, free it */
5922 if (Buffer != LocalBuffer)
5923 {
5924 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
5925 }
5926
5927 return Result;
5928 }
5929
5930
5931 /*
5932 * @implemented
5933 */
5934 BOOL
5935 APIENTRY
5936 NtGdiGetCharABCWidthsW(
5937 IN HDC hDC,
5938 IN UINT FirstChar,
5939 IN ULONG Count,
5940 IN OPTIONAL PWCHAR UnSafepwch,
5941 IN FLONG fl,
5942 OUT PVOID Buffer)
5943 {
5944 LPABC SafeBuff;
5945 LPABCFLOAT SafeBuffF = NULL;
5946 PDC dc;
5947 PDC_ATTR pdcattr;
5948 PTEXTOBJ TextObj;
5949 PFONTGDI FontGDI;
5950 FT_Face face;
5951 FT_CharMap charmap, found = NULL;
5952 UINT i, glyph_index, BufferSize;
5953 HFONT hFont = 0;
5954 NTSTATUS Status = STATUS_SUCCESS;
5955 PMATRIX pmxWorldToDevice;
5956 PWCHAR Safepwch = NULL;
5957 LOGFONTW *plf;
5958
5959 if (!Buffer)
5960 {
5961 EngSetLastError(ERROR_INVALID_PARAMETER);
5962 return FALSE;
5963 }
5964
5965 if (UnSafepwch)
5966 {
5967 UINT pwchSize = Count * sizeof(WCHAR);
5968 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
5969
5970 if(!Safepwch)
5971 {
5972 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5973 return FALSE;
5974 }
5975
5976 _SEH2_TRY
5977 {
5978 ProbeForRead(UnSafepwch, pwchSize, 1);
5979 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
5980 }
5981 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5982 {
5983 Status = _SEH2_GetExceptionCode();
5984 }
5985 _SEH2_END;
5986 }
5987
5988 if (!NT_SUCCESS(Status))
5989 {
5990 if(Safepwch)
5991 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
5992
5993 EngSetLastError(Status);
5994 return FALSE;
5995 }
5996
5997 BufferSize = Count * sizeof(ABC); // Same size!
5998 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
5999 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
6000 if (SafeBuff == NULL)
6001 {
6002
6003 if(Safepwch)
6004 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6005
6006 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6007 return FALSE;
6008 }
6009
6010 dc = DC_LockDc(hDC);
6011 if (dc == NULL)
6012 {
6013 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6014
6015 if(Safepwch)
6016 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6017
6018 EngSetLastError(ERROR_INVALID_HANDLE);
6019 return FALSE;
6020 }
6021 pdcattr = dc->pdcattr;
6022 hFont = pdcattr->hlfntNew;
6023 TextObj = RealizeFontInit(hFont);
6024
6025 /* Get the DC's world-to-device transformation matrix */
6026 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6027 DC_UnlockDc(dc);
6028
6029 if (TextObj == NULL)
6030 {
6031 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6032
6033 if(Safepwch)
6034 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6035
6036 EngSetLastError(ERROR_INVALID_HANDLE);
6037 return FALSE;
6038 }
6039
6040 FontGDI = ObjToGDI(TextObj->Font, FONT);
6041
6042 face = FontGDI->SharedFace->Face;
6043 if (face->charmap == NULL)
6044 {
6045 for (i = 0; i < (UINT)face->num_charmaps; i++)
6046 {
6047 charmap = face->charmaps[i];
6048 if (charmap->encoding != 0)
6049 {
6050 found = charmap;
6051 break;
6052 }
6053 }
6054
6055 if (!found)
6056 {
6057 DPRINT1("WARNING: Could not find desired charmap!\n");
6058 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6059
6060 if(Safepwch)
6061 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6062
6063 EngSetLastError(ERROR_INVALID_HANDLE);
6064 return FALSE;
6065 }
6066
6067 IntLockFreeType;
6068 FT_Set_Charmap(face, found);
6069 IntUnLockFreeType;
6070 }
6071
6072 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6073 IntLockFreeType;
6074 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
6075 FtSetCoordinateTransform(face, pmxWorldToDevice);
6076
6077 for (i = FirstChar; i < FirstChar+Count; i++)
6078 {
6079 int adv, lsb, bbx, left, right;
6080
6081 if (Safepwch)
6082 {
6083 if (fl & GCABCW_INDICES)
6084 glyph_index = Safepwch[i - FirstChar];
6085 else
6086 glyph_index = FT_Get_Char_Index(face, Safepwch[i - FirstChar]);
6087 }
6088 else
6089 {
6090 if (fl & GCABCW_INDICES)
6091 glyph_index = i;
6092 else
6093 glyph_index = FT_Get_Char_Index(face, i);
6094 }
6095 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6096
6097 left = (INT)face->glyph->metrics.horiBearingX & -64;
6098 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
6099 adv = (face->glyph->advance.x + 32) >> 6;
6100
6101 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
6102 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
6103
6104 lsb = left >> 6;
6105 bbx = (right - left) >> 6;
6106 /*
6107 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
6108 */
6109 if (!fl)
6110 {
6111 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
6112 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
6113 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
6114 }
6115 else
6116 {
6117 SafeBuff[i - FirstChar].abcA = lsb;
6118 SafeBuff[i - FirstChar].abcB = bbx;
6119 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
6120 }
6121 }
6122 IntUnLockFreeType;
6123 TEXTOBJ_UnlockText(TextObj);
6124 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6125
6126 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6127
6128 if(Safepwch)
6129 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6130
6131 if (! NT_SUCCESS(Status))
6132 {
6133 SetLastNtError(Status);
6134 return FALSE;
6135 }
6136
6137 DPRINT("NtGdiGetCharABCWidths Worked!\n");
6138 return TRUE;
6139 }
6140
6141 /*
6142 * @implemented
6143 */
6144 BOOL
6145 APIENTRY
6146 NtGdiGetCharWidthW(
6147 IN HDC hDC,
6148 IN UINT FirstChar,
6149 IN UINT Count,
6150 IN OPTIONAL PWCHAR UnSafepwc,
6151 IN FLONG fl,
6152 OUT PVOID Buffer)
6153 {
6154 NTSTATUS Status = STATUS_SUCCESS;
6155 LPINT SafeBuff;
6156 PFLOAT SafeBuffF = NULL;
6157 PDC dc;
6158 PDC_ATTR pdcattr;
6159 PTEXTOBJ TextObj;
6160 PFONTGDI FontGDI;
6161 FT_Face face;
6162 FT_CharMap charmap, found = NULL;
6163 UINT i, glyph_index, BufferSize;
6164 HFONT hFont = 0;
6165 PMATRIX pmxWorldToDevice;
6166 PWCHAR Safepwc = NULL;
6167 LOGFONTW *plf;
6168
6169 if (UnSafepwc)
6170 {
6171 UINT pwcSize = Count * sizeof(WCHAR);
6172 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6173
6174 if(!Safepwc)
6175 {
6176 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6177 return FALSE;
6178 }
6179 _SEH2_TRY
6180 {
6181 ProbeForRead(UnSafepwc, pwcSize, 1);
6182 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6183 }
6184 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6185 {
6186 Status = _SEH2_GetExceptionCode();
6187 }
6188 _SEH2_END;
6189 }
6190
6191 if (!NT_SUCCESS(Status))
6192 {
6193 EngSetLastError(Status);
6194 return FALSE;
6195 }
6196
6197 BufferSize = Count * sizeof(INT); // Same size!
6198 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6199 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
6200 if (SafeBuff == NULL)
6201 {
6202 if(Safepwc)
6203 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6204
6205 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6206 return FALSE;
6207 }
6208
6209 dc = DC_LockDc(hDC);
6210 if (dc == NULL)
6211 {
6212 if(Safepwc)
6213 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6214
6215 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6216 EngSetLastError(ERROR_INVALID_HANDLE);
6217 return FALSE;
6218 }
6219 pdcattr = dc->pdcattr;
6220 hFont = pdcattr->hlfntNew;
6221 TextObj = RealizeFontInit(hFont);
6222 /* Get the DC's world-to-device transformation matrix */
6223 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6224 DC_UnlockDc(dc);
6225
6226 if (TextObj == NULL)
6227 {
6228 if(Safepwc)
6229 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6230
6231 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6232 EngSetLastError(ERROR_INVALID_HANDLE);
6233 return FALSE;
6234 }
6235
6236 FontGDI = ObjToGDI(TextObj->Font, FONT);
6237
6238 face = FontGDI->SharedFace->Face;
6239 if (face->charmap == NULL)
6240 {
6241 for (i = 0; i < (UINT)face->num_charmaps; i++)
6242 {
6243 charmap = face->charmaps[i];
6244 if (charmap->encoding != 0)
6245 {
6246 found = charmap;
6247 break;
6248 }
6249 }
6250
6251 if (!found)
6252 {
6253 DPRINT1("WARNING: Could not find desired charmap!\n");
6254
6255 if(Safepwc)
6256 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6257
6258 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6259 EngSetLastError(ERROR_INVALID_HANDLE);
6260 return FALSE;
6261 }
6262
6263 IntLockFreeType;
6264 FT_Set_Charmap(face, found);
6265 IntUnLockFreeType;
6266 }
6267
6268 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6269 IntLockFreeType;
6270 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
6271 FtSetCoordinateTransform(face, pmxWorldToDevice);
6272
6273 for (i = FirstChar; i < FirstChar+Count; i++)
6274 {
6275 if (Safepwc)
6276 {
6277 if (fl & GCW_INDICES)
6278 glyph_index = Safepwc[i - FirstChar];
6279 else
6280 glyph_index = FT_Get_Char_Index(face, Safepwc[i - FirstChar]);
6281 }
6282 else
6283 {
6284 if (fl & GCW_INDICES)
6285 glyph_index = i;
6286 else
6287 glyph_index = FT_Get_Char_Index(face, i);
6288 }
6289 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6290 if (!fl)
6291 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
6292 else
6293 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
6294 }
6295 IntUnLockFreeType;
6296 TEXTOBJ_UnlockText(TextObj);
6297 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6298
6299 if(Safepwc)
6300 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6301
6302 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6303 return TRUE;
6304 }
6305
6306
6307 /*
6308 * @implemented
6309 */
6310 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
6311 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
6312 // NOTE: See also GreGetGlyphIndicesW.
6313 __kernel_entry
6314 W32KAPI
6315 DWORD
6316 APIENTRY
6317 NtGdiGetGlyphIndicesW(
6318 _In_ HDC hdc,
6319 _In_reads_opt_(cwc) LPCWSTR pwc,
6320 _In_ INT cwc,
6321 _Out_writes_opt_(cwc) LPWORD pgi,
6322 _In_ DWORD iMode)
6323 {
6324 PDC dc;
6325 PDC_ATTR pdcattr;
6326 PTEXTOBJ TextObj;
6327 PFONTGDI FontGDI;
6328 HFONT hFont = NULL;
6329 NTSTATUS Status = STATUS_SUCCESS;
6330 OUTLINETEXTMETRICW *potm;
6331 INT i;
6332 WCHAR DefChar = 0xffff;
6333 PWSTR Buffer = NULL;
6334 ULONG Size, pwcSize;
6335 PWSTR Safepwc = NULL;
6336 LPCWSTR UnSafepwc = pwc;
6337 LPWORD UnSafepgi = pgi;
6338
6339 /* Check for integer overflow */
6340 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN
6341 return GDI_ERROR;
6342
6343 if (!UnSafepwc && !UnSafepgi)
6344 return cwc;
6345
6346 if (!UnSafepwc || !UnSafepgi)
6347 {
6348 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
6349 return GDI_ERROR;
6350 }
6351
6352 // TODO: Special undocumented case!
6353 if (!pwc && !pgi && (cwc == 0))
6354 {
6355 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n");
6356 return 0;
6357 }
6358
6359 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825
6360 if (cwc == 0)
6361 {
6362 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n");
6363 return GDI_ERROR;
6364 }
6365
6366 dc = DC_LockDc(hdc);
6367 if (!dc)
6368 {
6369 return GDI_ERROR;
6370 }
6371 pdcattr = dc->pdcattr;
6372 hFont = pdcattr->hlfntNew;
6373 TextObj = RealizeFontInit(hFont);
6374 DC_UnlockDc(dc);
6375 if (!TextObj)
6376 {
6377 return GDI_ERROR;
6378 }
6379
6380 FontGDI = ObjToGDI(TextObj->Font, FONT);
6381 TEXTOBJ_UnlockText(TextObj);
6382
6383 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
6384 if (!Buffer)
6385 {
6386 return GDI_ERROR;
6387 }
6388
6389 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
6390 {
6391 DefChar = 0xffff;
6392 }
6393 else
6394 {
6395 FT_Face Face = FontGDI->SharedFace->Face;
6396 if (FT_IS_SFNT(Face))
6397 {
6398 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
6399 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(Face, pOS2->usDefaultChar) : 0);
6400 }
6401 else
6402 {
6403 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
6404 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
6405 if (!potm)
6406 {
6407 cwc = GDI_ERROR;
6408 goto ErrorRet;
6409 }
6410 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
6411 if (Size)
6412 DefChar = potm->otmTextMetrics.tmDefaultChar;
6413 ExFreePoolWithTag(potm, GDITAG_TEXT);
6414 }
6415 }
6416
6417 pwcSize = cwc * sizeof(WCHAR);
6418 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6419
6420 if (!Safepwc)
6421 {
6422 Status = STATUS_NO_MEMORY;
6423 goto ErrorRet;
6424 }
6425
6426 _SEH2_TRY
6427 {
6428 ProbeForRead(UnSafepwc, pwcSize, 1);
6429 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6430 }
6431 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6432 {
6433 Status = _SEH2_GetExceptionCode();
6434 }
6435 _SEH2_END;
6436
6437 if (!NT_SUCCESS(Status)) goto ErrorRet;
6438
6439 IntLockFreeType;
6440
6441 for (i = 0; i < cwc; i++)
6442 {
6443 Buffer[i] = FT_Get_Char_Index(FontGDI->SharedFace->Face, Safepwc[i]);
6444 if (Buffer[i] == 0)
6445 {
6446 Buffer[i] = DefChar;
6447 }
6448 }
6449
6450 IntUnLockFreeType;
6451
6452 _SEH2_TRY
6453 {
6454 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
6455 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
6456 }
6457 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6458 {
6459 Status = _SEH2_GetExceptionCode();
6460 }
6461 _SEH2_END;
6462
6463 ErrorRet:
6464 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6465 if (Safepwc != NULL)
6466 {
6467 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6468 }
6469 if (NT_SUCCESS(Status)) return cwc;
6470 return GDI_ERROR;
6471 }
6472
6473 /* EOF */