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