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