[WIN32K] -Use RtlStringCchCopyW instead of RtlStringCbCopyW in SubstituteFontRecurse...
[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 typedef struct FontFamilyInfoCallbackContext
2507 {
2508 LPLOGFONTW LogFont;
2509 PFONTFAMILYINFO Info;
2510 DWORD Count;
2511 DWORD Size;
2512 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
2513
2514 _Function_class_(RTL_QUERY_REGISTRY_ROUTINE)
2515 static NTSTATUS APIENTRY
2516 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
2517 IN PVOID ValueData, IN ULONG ValueLength,
2518 IN PVOID Context, IN PVOID EntryContext)
2519 {
2520 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
2521 UNICODE_STRING RegistryName, RegistryValue;
2522 int Existing;
2523 PFONTGDI FontGDI;
2524
2525 if (REG_SZ != ValueType)
2526 {
2527 return STATUS_SUCCESS;
2528 }
2529 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
2530 RtlInitUnicodeString(&RegistryName, ValueName);
2531
2532 /* Do we need to include this font family? */
2533 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
2534 min(InfoContext->Count, InfoContext->Size)))
2535 {
2536 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
2537 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
2538 min(InfoContext->Count, InfoContext->Size));
2539 if (0 <= Existing)
2540 {
2541 /* We already have the information about the "real" font. Just copy it */
2542 if (InfoContext->Count < InfoContext->Size)
2543 {
2544 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
2545 RtlStringCbCopyNW(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
2546 sizeof(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName),
2547 RegistryName.Buffer,
2548 RegistryName.Length);
2549 }
2550 InfoContext->Count++;
2551 return STATUS_SUCCESS;
2552 }
2553
2554 /* Try to find information about the "real" font */
2555 FontGDI = FindFaceNameInLists(&RegistryValue);
2556 if (NULL == FontGDI)
2557 {
2558 /* "Real" font not found, discard this registry entry */
2559 return STATUS_SUCCESS;
2560 }
2561
2562 /* Return info about the "real" font but with the name of the alias */
2563 if (InfoContext->Count < InfoContext->Size)
2564 {
2565 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
2566 RegistryName.Buffer, NULL, FontGDI);
2567 }
2568 InfoContext->Count++;
2569 return STATUS_SUCCESS;
2570 }
2571
2572 return STATUS_SUCCESS;
2573 }
2574
2575 static BOOLEAN FASTCALL
2576 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
2577 PFONTFAMILYINFO Info,
2578 DWORD *Count,
2579 DWORD Size)
2580 {
2581 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2582 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
2583 NTSTATUS Status;
2584
2585 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
2586 The real work is done in the registry callback function */
2587 Context.LogFont = LogFont;
2588 Context.Info = Info;
2589 Context.Count = *Count;
2590 Context.Size = Size;
2591
2592 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
2593 QueryTable[0].Flags = 0;
2594 QueryTable[0].Name = NULL;
2595 QueryTable[0].EntryContext = NULL;
2596 QueryTable[0].DefaultType = REG_NONE;
2597 QueryTable[0].DefaultData = NULL;
2598 QueryTable[0].DefaultLength = 0;
2599
2600 QueryTable[1].QueryRoutine = NULL;
2601 QueryTable[1].Name = NULL;
2602
2603 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2604 L"FontSubstitutes",
2605 QueryTable,
2606 &Context,
2607 NULL);
2608 if (NT_SUCCESS(Status))
2609 {
2610 *Count = Context.Count;
2611 }
2612
2613 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
2614 }
2615
2616 BOOL
2617 FASTCALL
2618 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
2619 {
2620 if ( lprs )
2621 {
2622 lprs->nSize = sizeof(RASTERIZER_STATUS);
2623 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
2624 lprs->nLanguageID = gusLanguageID;
2625 return TRUE;
2626 }
2627 EngSetLastError(ERROR_INVALID_PARAMETER);
2628 return FALSE;
2629 }
2630
2631 static
2632 BOOL
2633 SameScaleMatrix(
2634 PMATRIX pmx1,
2635 PMATRIX pmx2)
2636 {
2637 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
2638 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
2639 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
2640 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
2641 }
2642
2643 FT_BitmapGlyph APIENTRY
2644 ftGdiGlyphCacheGet(
2645 FT_Face Face,
2646 INT GlyphIndex,
2647 INT Height,
2648 PMATRIX pmx)
2649 {
2650 PLIST_ENTRY CurrentEntry;
2651 PFONT_CACHE_ENTRY FontEntry;
2652
2653 ASSERT_FREETYPE_LOCK_HELD();
2654
2655 CurrentEntry = FontCacheListHead.Flink;
2656 while (CurrentEntry != &FontCacheListHead)
2657 {
2658 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
2659 if ((FontEntry->Face == Face) &&
2660 (FontEntry->GlyphIndex == GlyphIndex) &&
2661 (FontEntry->Height == Height) &&
2662 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
2663 break;
2664 CurrentEntry = CurrentEntry->Flink;
2665 }
2666
2667 if (CurrentEntry == &FontCacheListHead)
2668 {
2669 return NULL;
2670 }
2671
2672 RemoveEntryList(CurrentEntry);
2673 InsertHeadList(&FontCacheListHead, CurrentEntry);
2674 return FontEntry->BitmapGlyph;
2675 }
2676
2677 /* no cache */
2678 FT_BitmapGlyph APIENTRY
2679 ftGdiGlyphSet(
2680 FT_Face Face,
2681 FT_GlyphSlot GlyphSlot,
2682 FT_Render_Mode RenderMode)
2683 {
2684 FT_Glyph Glyph;
2685 INT error;
2686 FT_Bitmap AlignedBitmap;
2687 FT_BitmapGlyph BitmapGlyph;
2688
2689 error = FT_Get_Glyph(GlyphSlot, &Glyph);
2690 if (error)
2691 {
2692 DPRINT1("Failure getting glyph.\n");
2693 return NULL;
2694 }
2695
2696 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2697 if (error)
2698 {
2699 FT_Done_Glyph(Glyph);
2700 DPRINT1("Failure rendering glyph.\n");
2701 return NULL;
2702 }
2703
2704 BitmapGlyph = (FT_BitmapGlyph)Glyph;
2705 FT_Bitmap_New(&AlignedBitmap);
2706 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2707 {
2708 DPRINT1("Conversion failed\n");
2709 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2710 return NULL;
2711 }
2712
2713 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2714 BitmapGlyph->bitmap = AlignedBitmap;
2715
2716 return BitmapGlyph;
2717 }
2718
2719 FT_BitmapGlyph APIENTRY
2720 ftGdiGlyphCacheSet(
2721 FT_Face Face,
2722 INT GlyphIndex,
2723 INT Height,
2724 PMATRIX pmx,
2725 FT_GlyphSlot GlyphSlot,
2726 FT_Render_Mode RenderMode)
2727 {
2728 FT_Glyph GlyphCopy;
2729 INT error;
2730 PFONT_CACHE_ENTRY NewEntry;
2731 FT_Bitmap AlignedBitmap;
2732 FT_BitmapGlyph BitmapGlyph;
2733
2734 ASSERT_FREETYPE_LOCK_HELD();
2735
2736 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2737 if (error)
2738 {
2739 DPRINT1("Failure caching glyph.\n");
2740 return NULL;
2741 };
2742
2743 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2744 if (error)
2745 {
2746 FT_Done_Glyph(GlyphCopy);
2747 DPRINT1("Failure rendering glyph.\n");
2748 return NULL;
2749 };
2750
2751 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
2752 if (!NewEntry)
2753 {
2754 DPRINT1("Alloc failure caching glyph.\n");
2755 FT_Done_Glyph(GlyphCopy);
2756 return NULL;
2757 }
2758
2759 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2760 FT_Bitmap_New(&AlignedBitmap);
2761 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2762 {
2763 DPRINT1("Conversion failed\n");
2764 ExFreePoolWithTag(NewEntry, TAG_FONT);
2765 FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
2766 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2767 return NULL;
2768 }
2769
2770 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2771 BitmapGlyph->bitmap = AlignedBitmap;
2772
2773 NewEntry->GlyphIndex = GlyphIndex;
2774 NewEntry->Face = Face;
2775 NewEntry->BitmapGlyph = BitmapGlyph;
2776 NewEntry->Height = Height;
2777 NewEntry->mxWorldToDevice = *pmx;
2778
2779 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
2780 if (++FontCacheNumEntries > MAX_FONT_CACHE)
2781 {
2782 NewEntry = CONTAINING_RECORD(FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
2783 RemoveCachedEntry(NewEntry);
2784 }
2785
2786 return BitmapGlyph;
2787 }
2788
2789
2790 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2791 {
2792 pt->x.value = vec->x >> 6;
2793 pt->x.fract = (vec->x & 0x3f) << 10;
2794 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2795 pt->y.value = vec->y >> 6;
2796 pt->y.fract = (vec->y & 0x3f) << 10;
2797 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2798 }
2799
2800 /*
2801 This function builds an FT_Fixed from a float. It puts the integer part
2802 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2803 It fails if the integer part of the float number is greater than SHORT_MAX.
2804 */
2805 static __inline FT_Fixed FT_FixedFromFloat(float f)
2806 {
2807 short value = f;
2808 unsigned short fract = (f - value) * 0xFFFF;
2809 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2810 }
2811
2812 /*
2813 This function builds an FT_Fixed from a FIXED. It simply put f.value
2814 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2815 */
2816 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2817 {
2818 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2819 }
2820
2821 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2822 {
2823 TTPOLYGONHEADER *pph;
2824 TTPOLYCURVE *ppc;
2825 int needed = 0, point = 0, contour, first_pt;
2826 unsigned int pph_start, cpfx;
2827 DWORD type;
2828
2829 for (contour = 0; contour < outline->n_contours; contour++)
2830 {
2831 /* Ignore contours containing one point */
2832 if (point == outline->contours[contour])
2833 {
2834 point++;
2835 continue;
2836 }
2837
2838 pph_start = needed;
2839 pph = (TTPOLYGONHEADER *)(buf + needed);
2840 first_pt = point;
2841 if (buf)
2842 {
2843 pph->dwType = TT_POLYGON_TYPE;
2844 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2845 }
2846 needed += sizeof(*pph);
2847 point++;
2848 while (point <= outline->contours[contour])
2849 {
2850 ppc = (TTPOLYCURVE *)(buf + needed);
2851 type = outline->tags[point] & FT_Curve_Tag_On ?
2852 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2853 cpfx = 0;
2854 do
2855 {
2856 if (buf)
2857 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2858 cpfx++;
2859 point++;
2860 } while (point <= outline->contours[contour] &&
2861 (outline->tags[point] & FT_Curve_Tag_On) ==
2862 (outline->tags[point-1] & FT_Curve_Tag_On));
2863 /* At the end of a contour Windows adds the start point, but
2864 only for Beziers */
2865 if (point > outline->contours[contour] &&
2866 !(outline->tags[point-1] & FT_Curve_Tag_On))
2867 {
2868 if (buf)
2869 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2870 cpfx++;
2871 }
2872 else if (point <= outline->contours[contour] &&
2873 outline->tags[point] & FT_Curve_Tag_On)
2874 {
2875 /* add closing pt for bezier */
2876 if (buf)
2877 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2878 cpfx++;
2879 point++;
2880 }
2881 if (buf)
2882 {
2883 ppc->wType = type;
2884 ppc->cpfx = cpfx;
2885 }
2886 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2887 }
2888 if (buf)
2889 pph->cb = needed - pph_start;
2890 }
2891 return needed;
2892 }
2893
2894 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2895 {
2896 /* Convert the quadratic Beziers to cubic Beziers.
2897 The parametric eqn for a cubic Bezier is, from PLRM:
2898 r(t) = at^3 + bt^2 + ct + r0
2899 with the control points:
2900 r1 = r0 + c/3
2901 r2 = r1 + (c + b)/3
2902 r3 = r0 + c + b + a
2903
2904 A quadratic Bezier has the form:
2905 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2906
2907 So equating powers of t leads to:
2908 r1 = 2/3 p1 + 1/3 p0
2909 r2 = 2/3 p1 + 1/3 p2
2910 and of course r0 = p0, r3 = p2
2911 */
2912 int contour, point = 0, first_pt;
2913 TTPOLYGONHEADER *pph;
2914 TTPOLYCURVE *ppc;
2915 DWORD pph_start, cpfx, type;
2916 FT_Vector cubic_control[4];
2917 unsigned int needed = 0;
2918
2919 for (contour = 0; contour < outline->n_contours; contour++)
2920 {
2921 pph_start = needed;
2922 pph = (TTPOLYGONHEADER *)(buf + needed);
2923 first_pt = point;
2924 if (buf)
2925 {
2926 pph->dwType = TT_POLYGON_TYPE;
2927 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2928 }
2929 needed += sizeof(*pph);
2930 point++;
2931 while (point <= outline->contours[contour])
2932 {
2933 ppc = (TTPOLYCURVE *)(buf + needed);
2934 type = outline->tags[point] & FT_Curve_Tag_On ?
2935 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2936 cpfx = 0;
2937 do
2938 {
2939 if (type == TT_PRIM_LINE)
2940 {
2941 if (buf)
2942 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2943 cpfx++;
2944 point++;
2945 }
2946 else
2947 {
2948 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2949 so cpfx = 3n */
2950
2951 /* FIXME: Possible optimization in endpoint calculation
2952 if there are two consecutive curves */
2953 cubic_control[0] = outline->points[point-1];
2954 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2955 {
2956 cubic_control[0].x += outline->points[point].x + 1;
2957 cubic_control[0].y += outline->points[point].y + 1;
2958 cubic_control[0].x >>= 1;
2959 cubic_control[0].y >>= 1;
2960 }
2961 if (point+1 > outline->contours[contour])
2962 cubic_control[3] = outline->points[first_pt];
2963 else
2964 {
2965 cubic_control[3] = outline->points[point+1];
2966 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2967 {
2968 cubic_control[3].x += outline->points[point].x + 1;
2969 cubic_control[3].y += outline->points[point].y + 1;
2970 cubic_control[3].x >>= 1;
2971 cubic_control[3].y >>= 1;
2972 }
2973 }
2974 /* r1 = 1/3 p0 + 2/3 p1
2975 r2 = 1/3 p2 + 2/3 p1 */
2976 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2977 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2978 cubic_control[2] = cubic_control[1];
2979 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2980 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2981 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2982 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2983 if (buf)
2984 {
2985 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2986 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2987 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2988 }
2989 cpfx += 3;
2990 point++;
2991 }
2992 } while (point <= outline->contours[contour] &&
2993 (outline->tags[point] & FT_Curve_Tag_On) ==
2994 (outline->tags[point-1] & FT_Curve_Tag_On));
2995 /* At the end of a contour Windows adds the start point,
2996 but only for Beziers and we've already done that.
2997 */
2998 if (point <= outline->contours[contour] &&
2999 outline->tags[point] & FT_Curve_Tag_On)
3000 {
3001 /* This is the closing pt of a bezier, but we've already
3002 added it, so just inc point and carry on */
3003 point++;
3004 }
3005 if (buf)
3006 {
3007 ppc->wType = type;
3008 ppc->cpfx = cpfx;
3009 }
3010 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3011 }
3012 if (buf)
3013 pph->cb = needed - pph_start;
3014 }
3015 return needed;
3016 }
3017
3018 static INT
3019 IntRequestFontSize(PDC dc, FT_Face face, LONG Width, LONG Height)
3020 {
3021 FT_Size_RequestRec req;
3022
3023 if (Width < 0)
3024 Width = -Width;
3025
3026 if (Height < 0)
3027 {
3028 Height = -Height;
3029 }
3030 if (Height == 0)
3031 {
3032 Height = dc->ppdev->devinfo.lfDefaultFont.lfHeight;
3033 }
3034 if (Height == 0)
3035 {
3036 Height = Width;
3037 }
3038
3039 if (Height < 1)
3040 Height = 1;
3041
3042 if (Width > 0xFFFFU)
3043 Width = 0xFFFFU;
3044 if (Height > 0xFFFFU)
3045 Height = 0xFFFFU;
3046
3047 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
3048 req.width = (FT_Long)(Width << 6);
3049 req.height = (FT_Long)(Height << 6);
3050 req.horiResolution = 0;
3051 req.vertResolution = 0;
3052 return FT_Request_Size(face, &req);
3053 }
3054
3055 BOOL
3056 FASTCALL
3057 TextIntUpdateSize(PDC dc,
3058 PTEXTOBJ TextObj,
3059 PFONTGDI FontGDI,
3060 BOOL bDoLock)
3061 {
3062 FT_Face face;
3063 INT error, n;
3064 FT_CharMap charmap, found;
3065 LOGFONTW *plf;
3066
3067 if (bDoLock)
3068 IntLockFreeType;
3069
3070 face = FontGDI->SharedFace->Face;
3071 if (face->charmap == NULL)
3072 {
3073 DPRINT("WARNING: No charmap selected!\n");
3074 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3075
3076 found = NULL;
3077 for (n = 0; n < face->num_charmaps; n++)
3078 {
3079 charmap = face->charmaps[n];
3080 DPRINT("Found charmap encoding: %i\n", charmap->encoding);
3081 if (charmap->encoding != 0)
3082 {
3083 found = charmap;
3084 break;
3085 }
3086 }
3087 if (!found)
3088 {
3089 DPRINT1("WARNING: Could not find desired charmap!\n");
3090 }
3091 else
3092 {
3093 error = FT_Set_Charmap(face, found);
3094 if (error)
3095 {
3096 DPRINT1("WARNING: Could not set the charmap!\n");
3097 }
3098 }
3099 }
3100
3101 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3102
3103 error = IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
3104
3105 if (bDoLock)
3106 IntUnLockFreeType;
3107
3108 if (error)
3109 {
3110 DPRINT1("Error in setting pixel sizes: %d\n", error);
3111 return FALSE;
3112 }
3113
3114 return TRUE;
3115 }
3116
3117
3118 /*
3119 * Based on WineEngGetGlyphOutline
3120 *
3121 */
3122 ULONG
3123 FASTCALL
3124 ftGdiGetGlyphOutline(
3125 PDC dc,
3126 WCHAR wch,
3127 UINT iFormat,
3128 LPGLYPHMETRICS pgm,
3129 ULONG cjBuf,
3130 PVOID pvBuf,
3131 LPMAT2 pmat2,
3132 BOOL bIgnoreRotation)
3133 {
3134 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
3135 PDC_ATTR pdcattr;
3136 PTEXTOBJ TextObj;
3137 PFONTGDI FontGDI;
3138 HFONT hFont = 0;
3139 GLYPHMETRICS gm;
3140 ULONG Size;
3141 FT_Face ft_face;
3142 FT_UInt glyph_index;
3143 DWORD width, height, pitch, needed = 0;
3144 FT_Bitmap ft_bitmap;
3145 FT_Error error;
3146 INT left, right, top = 0, bottom = 0;
3147 FT_Angle angle = 0;
3148 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
3149 FLOAT eM11, widthRatio = 1.0;
3150 FT_Matrix transMat = identityMat;
3151 BOOL needsTransform = FALSE;
3152 INT orientation;
3153 LONG aveWidth;
3154 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
3155 OUTLINETEXTMETRICW *potm;
3156 XFORM xForm;
3157 LOGFONTW *plf;
3158
3159 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
3160 cjBuf, pvBuf, pmat2);
3161
3162 pdcattr = dc->pdcattr;
3163
3164 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
3165 eM11 = xForm.eM11;
3166
3167 hFont = pdcattr->hlfntNew;
3168 TextObj = RealizeFontInit(hFont);
3169
3170 if (!TextObj)
3171 {
3172 EngSetLastError(ERROR_INVALID_HANDLE);
3173 return GDI_ERROR;
3174 }
3175 FontGDI = ObjToGDI(TextObj->Font, FONT);
3176 ft_face = FontGDI->SharedFace->Face;
3177
3178 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3179 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
3180 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
3181
3182 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3183 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3184 if (!potm)
3185 {
3186 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3187 TEXTOBJ_UnlockText(TextObj);
3188 return GDI_ERROR;
3189 }
3190 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
3191 if (!Size)
3192 {
3193 /* FIXME: last error? */
3194 ExFreePoolWithTag(potm, GDITAG_TEXT);
3195 TEXTOBJ_UnlockText(TextObj);
3196 return GDI_ERROR;
3197 }
3198
3199 IntLockFreeType;
3200 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3201 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
3202
3203 TEXTOBJ_UnlockText(TextObj);
3204
3205 if (iFormat & GGO_GLYPH_INDEX)
3206 {
3207 glyph_index = wch;
3208 iFormat &= ~GGO_GLYPH_INDEX;
3209 }
3210 else glyph_index = FT_Get_Char_Index(ft_face, wch);
3211
3212 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
3213 load_flags |= FT_LOAD_NO_BITMAP;
3214
3215 if (iFormat & GGO_UNHINTED)
3216 {
3217 load_flags |= FT_LOAD_NO_HINTING;
3218 iFormat &= ~GGO_UNHINTED;
3219 }
3220
3221 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
3222 if (error)
3223 {
3224 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3225 IntUnLockFreeType;
3226 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
3227 return GDI_ERROR;
3228 }
3229 IntUnLockFreeType;
3230
3231 if (aveWidth && potm)
3232 {
3233 widthRatio = (FLOAT)aveWidth * eM11 /
3234 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
3235 }
3236
3237 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
3238 right = (INT)((ft_face->glyph->metrics.horiBearingX +
3239 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
3240
3241 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
3242 lsb = left >> 6;
3243 bbx = (right - left) >> 6;
3244
3245 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
3246
3247 IntLockFreeType;
3248
3249 /* Scaling transform */
3250 /*if (aveWidth)*/
3251 {
3252
3253 FT_Matrix ftmatrix;
3254 FLOATOBJ efTemp;
3255
3256 PMATRIX pmx = DC_pmxWorldToDevice(dc);
3257
3258 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
3259 efTemp = pmx->efM11;
3260 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3261 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
3262
3263 efTemp = pmx->efM12;
3264 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3265 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
3266
3267 efTemp = pmx->efM21;
3268 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3269 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
3270
3271 efTemp = pmx->efM22;
3272 FLOATOBJ_MulLong(&efTemp, 0x00010000);
3273 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
3274
3275 FT_Matrix_Multiply(&ftmatrix, &transMat);
3276 needsTransform = TRUE;
3277 }
3278
3279 /* Rotation transform */
3280 if (orientation)
3281 {
3282 FT_Matrix rotationMat;
3283 FT_Vector vecAngle;
3284 DPRINT("Rotation Trans!\n");
3285 angle = FT_FixedFromFloat((float)orientation / 10.0);
3286 FT_Vector_Unit(&vecAngle, angle);
3287 rotationMat.xx = vecAngle.x;
3288 rotationMat.xy = -vecAngle.y;
3289 rotationMat.yx = -rotationMat.xy;
3290 rotationMat.yy = rotationMat.xx;
3291 FT_Matrix_Multiply(&rotationMat, &transMat);
3292 needsTransform = TRUE;
3293 }
3294
3295 /* Extra transformation specified by caller */
3296 if (pmat2)
3297 {
3298 FT_Matrix extraMat;
3299 DPRINT("MAT2 Matrix Trans!\n");
3300 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
3301 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
3302 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
3303 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
3304 FT_Matrix_Multiply(&extraMat, &transMat);
3305 needsTransform = TRUE;
3306 }
3307
3308 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
3309
3310 if (!needsTransform)
3311 {
3312 DPRINT("No Need to be Transformed!\n");
3313 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
3314 bottom = (ft_face->glyph->metrics.horiBearingY -
3315 ft_face->glyph->metrics.height) & -64;
3316 gm.gmCellIncX = adv;
3317 gm.gmCellIncY = 0;
3318 }
3319 else
3320 {
3321 INT xc, yc;
3322 FT_Vector vec;
3323 for (xc = 0; xc < 2; xc++)
3324 {
3325 for (yc = 0; yc < 2; yc++)
3326 {
3327 vec.x = (ft_face->glyph->metrics.horiBearingX +
3328 xc * ft_face->glyph->metrics.width);
3329 vec.y = ft_face->glyph->metrics.horiBearingY -
3330 yc * ft_face->glyph->metrics.height;
3331 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
3332 FT_Vector_Transform(&vec, &transMat);
3333 if (xc == 0 && yc == 0)
3334 {
3335 left = right = vec.x;
3336 top = bottom = vec.y;
3337 }
3338 else
3339 {
3340 if (vec.x < left) left = vec.x;
3341 else if (vec.x > right) right = vec.x;
3342 if (vec.y < bottom) bottom = vec.y;
3343 else if (vec.y > top) top = vec.y;
3344 }
3345 }
3346 }
3347 left = left & -64;
3348 right = (right + 63) & -64;
3349 bottom = bottom & -64;
3350 top = (top + 63) & -64;
3351
3352 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
3353 vec.x = ft_face->glyph->metrics.horiAdvance;
3354 vec.y = 0;
3355 FT_Vector_Transform(&vec, &transMat);
3356 gm.gmCellIncX = (vec.x+63) >> 6;
3357 gm.gmCellIncY = -((vec.y+63) >> 6);
3358 }
3359 gm.gmBlackBoxX = (right - left) >> 6;
3360 gm.gmBlackBoxY = (top - bottom) >> 6;
3361 gm.gmptGlyphOrigin.x = left >> 6;
3362 gm.gmptGlyphOrigin.y = top >> 6;
3363
3364 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
3365 gm.gmCellIncX, gm.gmCellIncY,
3366 gm.gmBlackBoxX, gm.gmBlackBoxY,
3367 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
3368
3369 IntUnLockFreeType;
3370
3371
3372 if (iFormat == GGO_METRICS)
3373 {
3374 DPRINT("GGO_METRICS Exit!\n");
3375 *pgm = gm;
3376 return 1; /* FIXME */
3377 }
3378
3379 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
3380 {
3381 DPRINT1("Loaded a bitmap\n");
3382 return GDI_ERROR;
3383 }
3384
3385 switch (iFormat)
3386 {
3387 case GGO_BITMAP:
3388 width = gm.gmBlackBoxX;
3389 height = gm.gmBlackBoxY;
3390 pitch = ((width + 31) >> 5) << 2;
3391 needed = pitch * height;
3392
3393 if (!pvBuf || !cjBuf) break;
3394 if (!needed) return GDI_ERROR; /* empty glyph */
3395 if (needed > cjBuf)
3396 return GDI_ERROR;
3397
3398 switch (ft_face->glyph->format)
3399 {
3400 case ft_glyph_format_bitmap:
3401 {
3402 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3403 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
3404 INT h = min( height, ft_face->glyph->bitmap.rows );
3405 while (h--)
3406 {
3407 RtlCopyMemory(dst, src, w);
3408 src += ft_face->glyph->bitmap.pitch;
3409 dst += pitch;
3410 }
3411 break;
3412 }
3413
3414 case ft_glyph_format_outline:
3415 ft_bitmap.width = width;
3416 ft_bitmap.rows = height;
3417 ft_bitmap.pitch = pitch;
3418 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
3419 ft_bitmap.buffer = pvBuf;
3420
3421 IntLockFreeType;
3422 if (needsTransform)
3423 {
3424 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3425 }
3426 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3427 /* Note: FreeType will only set 'black' bits for us. */
3428 RtlZeroMemory(pvBuf, needed);
3429 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3430 IntUnLockFreeType;
3431 break;
3432
3433 default:
3434 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3435 return GDI_ERROR;
3436 }
3437 break;
3438
3439 case GGO_GRAY2_BITMAP:
3440 case GGO_GRAY4_BITMAP:
3441 case GGO_GRAY8_BITMAP:
3442 {
3443 unsigned int mult, row, col;
3444 BYTE *start, *ptr;
3445
3446 width = gm.gmBlackBoxX;
3447 height = gm.gmBlackBoxY;
3448 pitch = (width + 3) / 4 * 4;
3449 needed = pitch * height;
3450
3451 if (!pvBuf || !cjBuf) break;
3452 if (!needed) return GDI_ERROR; /* empty glyph */
3453 if (needed > cjBuf)
3454 return GDI_ERROR;
3455
3456 switch (ft_face->glyph->format)
3457 {
3458 case ft_glyph_format_bitmap:
3459 {
3460 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
3461 INT h = min( height, ft_face->glyph->bitmap.rows );
3462 INT x;
3463 while (h--)
3464 {
3465 for (x = 0; (UINT)x < pitch; x++)
3466 {
3467 if (x < ft_face->glyph->bitmap.width)
3468 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
3469 else
3470 dst[x] = 0;
3471 }
3472 src += ft_face->glyph->bitmap.pitch;
3473 dst += pitch;
3474 }
3475 break;
3476 }
3477 case ft_glyph_format_outline:
3478 {
3479 ft_bitmap.width = width;
3480 ft_bitmap.rows = height;
3481 ft_bitmap.pitch = pitch;
3482 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
3483 ft_bitmap.buffer = pvBuf;
3484
3485 IntLockFreeType;
3486 if (needsTransform)
3487 {
3488 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
3489 }
3490 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
3491 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
3492 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
3493 IntUnLockFreeType;
3494
3495 if (iFormat == GGO_GRAY2_BITMAP)
3496 mult = 4;
3497 else if (iFormat == GGO_GRAY4_BITMAP)
3498 mult = 16;
3499 else if (iFormat == GGO_GRAY8_BITMAP)
3500 mult = 64;
3501 else
3502 {
3503 return GDI_ERROR;
3504 }
3505
3506 start = pvBuf;
3507 for (row = 0; row < height; row++)
3508 {
3509 ptr = start;
3510 for (col = 0; col < width; col++, ptr++)
3511 {
3512 *ptr = (((int)*ptr) * mult + 128) / 256;
3513 }
3514 start += pitch;
3515 }
3516
3517 break;
3518 }
3519 default:
3520 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
3521 return GDI_ERROR;
3522 }
3523 }
3524
3525 case GGO_NATIVE:
3526 {
3527 FT_Outline *outline = &ft_face->glyph->outline;
3528
3529 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
3530
3531 IntLockFreeType;
3532 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
3533
3534 needed = get_native_glyph_outline(outline, cjBuf, NULL);
3535
3536 if (!pvBuf || !cjBuf)
3537 {
3538 IntUnLockFreeType;
3539 break;
3540 }
3541 if (needed > cjBuf)
3542 {
3543 IntUnLockFreeType;
3544 return GDI_ERROR;
3545 }
3546 get_native_glyph_outline(outline, cjBuf, pvBuf);
3547 IntUnLockFreeType;
3548 break;
3549 }
3550 case GGO_BEZIER:
3551 {
3552 FT_Outline *outline = &ft_face->glyph->outline;
3553 if (cjBuf == 0) pvBuf = NULL;
3554
3555 if (needsTransform && pvBuf)
3556 {
3557 IntLockFreeType;
3558 FT_Outline_Transform(outline, &transMat);
3559 IntUnLockFreeType;
3560 }
3561 needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
3562
3563 if (!pvBuf || !cjBuf)
3564 break;
3565 if (needed > cjBuf)
3566 return GDI_ERROR;
3567
3568 get_bezier_glyph_outline(outline, cjBuf, pvBuf);
3569 break;
3570 }
3571
3572 default:
3573 DPRINT1("Unsupported format %u\n", iFormat);
3574 return GDI_ERROR;
3575 }
3576
3577 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
3578 *pgm = gm;
3579 return needed;
3580 }
3581
3582 BOOL
3583 FASTCALL
3584 TextIntGetTextExtentPoint(PDC dc,
3585 PTEXTOBJ TextObj,
3586 LPCWSTR String,
3587 INT Count,
3588 ULONG MaxExtent,
3589 LPINT Fit,
3590 LPINT Dx,
3591 LPSIZE Size,
3592 FLONG fl)
3593 {
3594 PFONTGDI FontGDI;
3595 FT_Face face;
3596 FT_GlyphSlot glyph;
3597 FT_BitmapGlyph realglyph;
3598 INT error, glyph_index, i, previous;
3599 ULONGLONG TotalWidth = 0;
3600 BOOL use_kerning;
3601 FT_Render_Mode RenderMode;
3602 BOOLEAN Render;
3603 PMATRIX pmxWorldToDevice;
3604 LOGFONTW *plf;
3605 BOOL EmuBold, EmuItalic;
3606
3607 FontGDI = ObjToGDI(TextObj->Font, FONT);
3608
3609 face = FontGDI->SharedFace->Face;
3610 if (NULL != Fit)
3611 {
3612 *Fit = 0;
3613 }
3614
3615 IntLockFreeType;
3616
3617 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
3618
3619 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3620 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
3621 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
3622
3623 Render = IntIsFontRenderingEnabled();
3624 if (Render)
3625 RenderMode = IntGetFontRenderMode(plf);
3626 else
3627 RenderMode = FT_RENDER_MODE_MONO;
3628
3629
3630 /* Get the DC's world-to-device transformation matrix */
3631 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3632 FtSetCoordinateTransform(face, pmxWorldToDevice);
3633
3634 use_kerning = FT_HAS_KERNING(face);
3635 previous = 0;
3636
3637 for (i = 0; i < Count; i++)
3638 {
3639 if (fl & GTEF_INDICES)
3640 glyph_index = *String;
3641 else
3642 glyph_index = FT_Get_Char_Index(face, *String);
3643
3644 if (EmuBold || EmuItalic)
3645 realglyph = NULL;
3646 else
3647 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3648 plf->lfHeight, pmxWorldToDevice);
3649
3650 if (EmuBold || EmuItalic || !realglyph)
3651 {
3652 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3653 if (error)
3654 {
3655 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
3656 break;
3657 }
3658
3659 glyph = face->glyph;
3660 if (EmuBold || EmuItalic)
3661 {
3662 if (EmuBold)
3663 FT_GlyphSlot_Embolden(glyph);
3664 if (EmuItalic)
3665 FT_GlyphSlot_Oblique(glyph);
3666 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
3667 }
3668 else
3669 {
3670 realglyph = ftGdiGlyphCacheSet(face,
3671 glyph_index,
3672 plf->lfHeight,
3673 pmxWorldToDevice,
3674 glyph,
3675 RenderMode);
3676 }
3677
3678 if (!realglyph)
3679 {
3680 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3681 break;
3682 }
3683 }
3684
3685 /* Retrieve kerning distance */
3686 if (use_kerning && previous && glyph_index)
3687 {
3688 FT_Vector delta;
3689 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3690 TotalWidth += delta.x;
3691 }
3692
3693 TotalWidth += realglyph->root.advance.x >> 10;
3694
3695 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
3696 {
3697 *Fit = i + 1;
3698 }
3699 if (NULL != Dx)
3700 {
3701 Dx[i] = (TotalWidth + 32) >> 6;
3702 }
3703
3704 if (EmuBold || EmuItalic)
3705 {
3706 FT_Done_Glyph((FT_Glyph)realglyph);
3707 realglyph = NULL;
3708 }
3709
3710 previous = glyph_index;
3711 String++;
3712 }
3713 IntUnLockFreeType;
3714
3715 Size->cx = (TotalWidth + 32) >> 6;
3716 Size->cy = (plf->lfHeight == 0 ?
3717 dc->ppdev->devinfo.lfDefaultFont.lfHeight :
3718 abs(plf->lfHeight));
3719 Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
3720
3721 return TRUE;
3722 }
3723
3724
3725 INT
3726 FASTCALL
3727 ftGdiGetTextCharsetInfo(
3728 PDC Dc,
3729 LPFONTSIGNATURE lpSig,
3730 DWORD dwFlags)
3731 {
3732 PDC_ATTR pdcattr;
3733 UINT Ret = DEFAULT_CHARSET;
3734 INT i;
3735 HFONT hFont;
3736 PTEXTOBJ TextObj;
3737 PFONTGDI FontGdi;
3738 FONTSIGNATURE fs;
3739 TT_OS2 *pOS2;
3740 FT_Face Face;
3741 CHARSETINFO csi;
3742 DWORD cp, fs0;
3743 USHORT usACP, usOEM;
3744
3745 pdcattr = Dc->pdcattr;
3746 hFont = pdcattr->hlfntNew;
3747 TextObj = RealizeFontInit(hFont);
3748
3749 if (!TextObj)
3750 {
3751 EngSetLastError(ERROR_INVALID_HANDLE);
3752 return Ret;
3753 }
3754 FontGdi = ObjToGDI(TextObj->Font, FONT);
3755 Face = FontGdi->SharedFace->Face;
3756 TEXTOBJ_UnlockText(TextObj);
3757
3758 IntLockFreeType;
3759 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3760 IntUnLockFreeType;
3761 memset(&fs, 0, sizeof(FONTSIGNATURE));
3762 if (NULL != pOS2)
3763 {
3764 fs.fsCsb[0] = pOS2->ulCodePageRange1;
3765 fs.fsCsb[1] = pOS2->ulCodePageRange2;
3766 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3767 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3768 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3769 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3770 if (pOS2->version == 0)
3771 {
3772 FT_UInt dummy;
3773
3774 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
3775 fs.fsCsb[0] |= FS_LATIN1;
3776 else
3777 fs.fsCsb[0] |= FS_SYMBOL;
3778 }
3779 }
3780 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
3781 if (fs.fsCsb[0] == 0)
3782 { /* Let's see if we can find any interesting cmaps */
3783 for (i = 0; i < Face->num_charmaps; i++)
3784 {
3785 switch (Face->charmaps[i]->encoding)
3786 {
3787 case FT_ENCODING_UNICODE:
3788 case FT_ENCODING_APPLE_ROMAN:
3789 fs.fsCsb[0] |= FS_LATIN1;
3790 break;
3791 case FT_ENCODING_MS_SYMBOL:
3792 fs.fsCsb[0] |= FS_SYMBOL;
3793 break;
3794 default:
3795 break;
3796 }
3797 }
3798 }
3799 if (lpSig)
3800 {
3801 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
3802 }
3803
3804 RtlGetDefaultCodePage(&usACP, &usOEM);
3805 cp = usACP;
3806
3807 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
3808 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
3809 {
3810 DPRINT("Hit 1\n");
3811 Ret = csi.ciCharset;
3812 goto Exit;
3813 }
3814
3815 for (i = 0; i < MAXTCIINDEX; i++)
3816 {
3817 fs0 = 1L << i;
3818 if (fs.fsCsb[0] & fs0)
3819 {
3820 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
3821 {
3822 // *cp = csi.ciACP;
3823 DPRINT("Hit 2\n");
3824 Ret = csi.ciCharset;
3825 goto Exit;
3826 }
3827 else
3828 DPRINT1("TCI failing on %x\n", fs0);
3829 }
3830 }
3831 Exit:
3832 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
3833 return (MAKELONG(csi.ciACP, csi.ciCharset));
3834 }
3835
3836
3837 DWORD
3838 FASTCALL
3839 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
3840 {
3841 DWORD size = 0;
3842 DWORD num_ranges = 0;
3843 FT_Face face = Font->SharedFace->Face;
3844
3845 if (face->charmap->encoding == FT_ENCODING_UNICODE)
3846 {
3847 FT_UInt glyph_code = 0;
3848 FT_ULong char_code, char_code_prev;
3849
3850 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
3851
3852 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3853 face->num_glyphs, glyph_code, char_code);
3854
3855 if (!glyph_code) return 0;
3856
3857 if (glyphset)
3858 {
3859 glyphset->ranges[0].wcLow = (USHORT)char_code;
3860 glyphset->ranges[0].cGlyphs = 0;
3861 glyphset->cGlyphsSupported = 0;
3862 }
3863
3864 num_ranges = 1;
3865 while (glyph_code)
3866 {
3867 if (char_code < char_code_prev)
3868 {
3869 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
3870 return 0;
3871 }
3872 if (char_code - char_code_prev > 1)
3873 {
3874 num_ranges++;
3875 if (glyphset)
3876 {
3877 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
3878 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
3879 glyphset->cGlyphsSupported++;
3880 }
3881 }
3882 else if (glyphset)
3883 {
3884 glyphset->ranges[num_ranges - 1].cGlyphs++;
3885 glyphset->cGlyphsSupported++;
3886 }
3887 char_code_prev = char_code;
3888 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
3889 }
3890 }
3891 else
3892 DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
3893
3894 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
3895 if (glyphset)
3896 {
3897 glyphset->cbThis = size;
3898 glyphset->cRanges = num_ranges;
3899 glyphset->flAccel = 0;
3900 }
3901 return size;
3902 }
3903
3904
3905 BOOL
3906 FASTCALL
3907 ftGdiGetTextMetricsW(
3908 HDC hDC,
3909 PTMW_INTERNAL ptmwi)
3910 {
3911 PDC dc;
3912 PDC_ATTR pdcattr;
3913 PTEXTOBJ TextObj;
3914 PFONTGDI FontGDI;
3915 FT_Face Face;
3916 TT_OS2 *pOS2;
3917 TT_HoriHeader *pHori;
3918 FT_WinFNT_HeaderRec Win;
3919 ULONG Error;
3920 NTSTATUS Status = STATUS_SUCCESS;
3921 LOGFONTW *plf;
3922
3923 if (!ptmwi)
3924 {
3925 EngSetLastError(STATUS_INVALID_PARAMETER);
3926 return FALSE;
3927 }
3928
3929 if (!(dc = DC_LockDc(hDC)))
3930 {
3931 EngSetLastError(ERROR_INVALID_HANDLE);
3932 return FALSE;
3933 }
3934 pdcattr = dc->pdcattr;
3935 TextObj = RealizeFontInit(pdcattr->hlfntNew);
3936 if (NULL != TextObj)
3937 {
3938 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3939 FontGDI = ObjToGDI(TextObj->Font, FONT);
3940
3941 Face = FontGDI->SharedFace->Face;
3942 IntLockFreeType;
3943 Error = IntRequestFontSize(dc, Face, plf->lfWidth, plf->lfHeight);
3944 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
3945 IntUnLockFreeType;
3946 if (0 != Error)
3947 {
3948 DPRINT1("Error in setting pixel sizes: %u\n", Error);
3949 Status = STATUS_UNSUCCESSFUL;
3950 }
3951 else
3952 {
3953 FT_Face Face = FontGDI->SharedFace->Face;
3954 Status = STATUS_SUCCESS;
3955
3956 IntLockFreeType;
3957 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3958 if (NULL == pOS2)
3959 {
3960 DPRINT1("Can't find OS/2 table - not TT font?\n");
3961 Status = STATUS_INTERNAL_ERROR;
3962 }
3963
3964 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
3965 if (NULL == pHori)
3966 {
3967 DPRINT1("Can't find HHEA table - not TT font?\n");
3968 Status = STATUS_INTERNAL_ERROR;
3969 }
3970
3971 Error = FT_Get_WinFNT_Header(Face, &Win);
3972
3973 IntUnLockFreeType;
3974
3975 if (NT_SUCCESS(Status))
3976 {
3977 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
3978
3979 /* FIXME: Fill Diff member */
3980 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
3981 }
3982 }
3983 TEXTOBJ_UnlockText(TextObj);
3984 }
3985 else
3986 {
3987 Status = STATUS_INVALID_HANDLE;
3988 }
3989 DC_UnlockDc(dc);
3990
3991 if (!NT_SUCCESS(Status))
3992 {
3993 SetLastNtError(Status);
3994 return FALSE;
3995 }
3996 return TRUE;
3997 }
3998
3999 DWORD
4000 FASTCALL
4001 ftGdiGetFontData(
4002 PFONTGDI FontGdi,
4003 DWORD Table,
4004 DWORD Offset,
4005 PVOID Buffer,
4006 DWORD Size)
4007 {
4008 DWORD Result = GDI_ERROR;
4009 FT_Face Face = FontGdi->SharedFace->Face;
4010
4011 IntLockFreeType;
4012
4013 if (FT_IS_SFNT(Face))
4014 {
4015 if (Table)
4016 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
4017 (Table << 8 & 0xFF0000);
4018
4019 if (!Buffer) Size = 0;
4020
4021 if (Buffer && Size)
4022 {
4023 FT_Error Error;
4024 FT_ULong Needed = 0;
4025
4026 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
4027
4028 if ( !Error && Needed < Size) Size = Needed;
4029 }
4030 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
4031 Result = Size;
4032 }
4033
4034 IntUnLockFreeType;
4035
4036 return Result;
4037 }
4038
4039 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
4040 static UINT
4041 GetFontPenalty(const LOGFONTW * LogFont,
4042 const OUTLINETEXTMETRICW * Otm,
4043 const char * style_name)
4044 {
4045 ULONG Penalty = 0;
4046 BYTE Byte;
4047 LONG Long;
4048 BOOL fFixedSys = FALSE, fNeedScaling = FALSE;
4049 const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
4050 const TEXTMETRICW * TM = &Otm->otmTextMetrics;
4051 WCHAR* ActualNameW;
4052
4053 ASSERT(Otm);
4054 ASSERT(LogFont);
4055 ASSERT(style_name);
4056
4057 /* FIXME: Aspect Penalty 30 */
4058 /* FIXME: IntSizeSynth Penalty 20 */
4059 /* FIXME: SmallPenalty Penalty 1 */
4060 /* FIXME: FaceNameSubst Penalty 500 */
4061
4062 if (_wcsicmp(LogFont->lfFaceName, L"System") == 0)
4063 {
4064 /* "System" font */
4065 if (TM->tmCharSet != UserCharSet)
4066 {
4067 /* CharSet Penalty 65000 */
4068 /* Requested charset does not match the candidate's. */
4069 Penalty += 65000;
4070 }
4071 }
4072 else if (_wcsicmp(LogFont->lfFaceName, L"FixedSys") == 0)
4073 {
4074 /* "FixedSys" font */
4075 if (TM->tmCharSet != UserCharSet)
4076 {
4077 /* CharSet Penalty 65000 */
4078 /* Requested charset does not match the candidate's. */
4079 Penalty += 65000;
4080 }
4081 fFixedSys = TRUE;
4082 }
4083 else /* Request is non-"System" font */
4084 {
4085 Byte = LogFont->lfCharSet;
4086 if (Byte == DEFAULT_CHARSET)
4087 {
4088 if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0)
4089 {
4090 if (Byte == ANSI_CHARSET)
4091 {
4092 DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
4093 }
4094 /* We assume SYMBOL_CHARSET for "Marlett" font */
4095 Byte = SYMBOL_CHARSET;
4096 }
4097 }
4098
4099 if (Byte != TM->tmCharSet)
4100 {
4101 if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
4102 {
4103 /* CharSet Penalty 65000 */
4104 /* Requested charset does not match the candidate's. */
4105 Penalty += 65000;
4106 }
4107 else
4108 {
4109 if (UserCharSet != TM->tmCharSet)
4110 {
4111 /* UNDOCUMENTED */
4112 Penalty += 100;
4113 if (ANSI_CHARSET != TM->tmCharSet)
4114 {
4115 /* UNDOCUMENTED */
4116 Penalty += 100;
4117 }
4118 }
4119 }
4120 }
4121 }
4122
4123 Byte = LogFont->lfOutPrecision;
4124 if (Byte == OUT_DEFAULT_PRECIS)
4125 Byte = OUT_OUTLINE_PRECIS; /* Is it OK? */
4126 switch (Byte)
4127 {
4128 case OUT_DEVICE_PRECIS:
4129 if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
4130 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
4131 {
4132 /* OutputPrecision Penalty 19000 */
4133 /* Requested OUT_STROKE_PRECIS, but the device can't do it
4134 or the candidate is not a vector font. */
4135 Penalty += 19000;
4136 }
4137 break;
4138 default:
4139 if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
4140 {
4141 /* OutputPrecision Penalty 19000 */
4142 /* Or OUT_STROKE_PRECIS not requested, and the candidate
4143 is a vector font that requires GDI support. */
4144 Penalty += 19000;
4145 }
4146 break;
4147 }
4148
4149 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4150 if (Byte == DEFAULT_PITCH)
4151 Byte = VARIABLE_PITCH;
4152 if (fFixedSys)
4153 {
4154 /* "FixedSys" font should be fixed-pitch */
4155 Byte = FIXED_PITCH;
4156 }
4157 if (Byte == FIXED_PITCH)
4158 {
4159 if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
4160 {
4161 /* FixedPitch Penalty 15000 */
4162 /* Requested a fixed pitch font, but the candidate is a
4163 variable pitch font. */
4164 Penalty += 15000;
4165 }
4166 }
4167 if (Byte == VARIABLE_PITCH)
4168 {
4169 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4170 {
4171 /* PitchVariable Penalty 350 */
4172 /* Requested a variable pitch font, but the candidate is not a
4173 variable pitch font. */
4174 Penalty += 350;
4175 }
4176 }
4177
4178 Byte = (LogFont->lfPitchAndFamily & 0x0F);
4179 if (Byte == DEFAULT_PITCH)
4180 {
4181 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
4182 {
4183 /* DefaultPitchFixed Penalty 1 */
4184 /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
4185 Penalty += 1;
4186 }
4187 }
4188
4189 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
4190
4191 if (LogFont->lfFaceName[0])
4192 {
4193 BOOL Found = FALSE;
4194
4195 /* localized family name */
4196 if (!Found)
4197 {
4198 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4199 }
4200 /* localized full name */
4201 if (!Found)
4202 {
4203 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
4204 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
4205 }
4206 if (!Found)
4207 {
4208 /* FaceName Penalty 10000 */
4209 /* Requested a face name, but the candidate's face name
4210 does not match. */
4211 Penalty += 10000;
4212 }
4213 }
4214
4215 Byte = (LogFont->lfPitchAndFamily & 0xF0);
4216 if (Byte != FF_DONTCARE)
4217 {
4218 if (Byte != (TM->tmPitchAndFamily & 0xF0))
4219 {
4220 /* Family Penalty 9000 */
4221 /* Requested a family, but the candidate's family is different. */
4222 Penalty += 9000;
4223 }
4224 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
4225 {
4226 /* FamilyUnknown Penalty 8000 */
4227 /* Requested a family, but the candidate has no family. */
4228 Penalty += 8000;
4229 }
4230 }
4231
4232 /* Is the candidate a non-vector font? */
4233 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4234 {
4235 /* Is lfHeight specified? */
4236 if (LogFont->lfHeight != 0)
4237 {
4238 if (labs(LogFont->lfHeight) < TM->tmHeight)
4239 {
4240 /* HeightBigger Penalty 600 */
4241 /* The candidate is a nonvector font and is bigger than the
4242 requested height. */
4243 Penalty += 600;
4244 /* HeightBiggerDifference Penalty 150 */
4245 /* The candidate is a raster font and is larger than the
4246 requested height. Penalty * height difference */
4247 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4248
4249 fNeedScaling = TRUE;
4250 }
4251 if (TM->tmHeight < labs(LogFont->lfHeight))
4252 {
4253 /* HeightSmaller Penalty 150 */
4254 /* The candidate is a raster font and is smaller than the
4255 requested height. Penalty * height difference */
4256 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
4257
4258 fNeedScaling = TRUE;
4259 }
4260 }
4261 }
4262
4263 switch (LogFont->lfPitchAndFamily & 0xF0)
4264 {
4265 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4266 switch (TM->tmPitchAndFamily & 0xF0)
4267 {
4268 case FF_DECORATIVE: case FF_SCRIPT:
4269 /* FamilyUnlikely Penalty 50 */
4270 /* Requested a roman/modern/swiss family, but the
4271 candidate is decorative/script. */
4272 Penalty += 50;
4273 break;
4274 default:
4275 break;
4276 }
4277 break;
4278 case FF_DECORATIVE: case FF_SCRIPT:
4279 switch (TM->tmPitchAndFamily & 0xF0)
4280 {
4281 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
4282 /* FamilyUnlikely Penalty 50 */
4283 /* Or requested decorative/script, and the candidate is
4284 roman/modern/swiss. */
4285 Penalty += 50;
4286 break;
4287 default:
4288 break;
4289 }
4290 default:
4291 break;
4292 }
4293
4294 if (LogFont->lfWidth != 0)
4295 {
4296 if (LogFont->lfWidth != TM->tmAveCharWidth)
4297 {
4298 /* Width Penalty 50 */
4299 /* Requested a nonzero width, but the candidate's width
4300 doesn't match. Penalty * width difference */
4301 Penalty += 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth);
4302
4303 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4304 fNeedScaling = TRUE;
4305 }
4306 }
4307
4308 if (fNeedScaling)
4309 {
4310 /* SizeSynth Penalty 50 */
4311 /* The candidate is a raster font that needs scaling by GDI. */
4312 Penalty += 50;
4313 }
4314
4315 if (!!LogFont->lfItalic != !!TM->tmItalic)
4316 {
4317 if (!LogFont->lfItalic && ItalicFromStyle(style_name))
4318 {
4319 /* Italic Penalty 4 */
4320 /* Requested font and candidate font do not agree on italic status,
4321 and the desired result cannot be simulated. */
4322 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
4323 Penalty += 40;
4324 }
4325 else if (LogFont->lfItalic && !ItalicFromStyle(style_name))
4326 {
4327 /* ItalicSim Penalty 1 */
4328 /* Requested italic font but the candidate is not italic,
4329 although italics can be simulated. */
4330 Penalty += 1;
4331 }
4332 }
4333
4334 if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
4335 {
4336 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
4337 {
4338 /* NotTrueType Penalty 4 */
4339 /* Requested OUT_TT_PRECIS, but the candidate is not a
4340 TrueType font. */
4341 Penalty += 4;
4342 }
4343 }
4344
4345 Long = LogFont->lfWeight;
4346 if (LogFont->lfWeight == FW_DONTCARE)
4347 Long = FW_NORMAL;
4348 if (Long != TM->tmWeight)
4349 {
4350 /* Weight Penalty 3 */
4351 /* The candidate's weight does not match the requested weight.
4352 Penalty * (weight difference/10) */
4353 Penalty += 3 * (labs(Long - TM->tmWeight) / 10);
4354 }
4355
4356 if (!LogFont->lfUnderline && TM->tmUnderlined)
4357 {
4358 /* Underline Penalty 3 */
4359 /* Requested font has no underline, but the candidate is
4360 underlined. */
4361 Penalty += 3;
4362 }
4363
4364 if (!LogFont->lfStrikeOut && TM->tmStruckOut)
4365 {
4366 /* StrikeOut Penalty 3 */
4367 /* Requested font has no strike-out, but the candidate is
4368 struck out. */
4369 Penalty += 3;
4370 }
4371
4372 /* Is the candidate a non-vector font? */
4373 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
4374 {
4375 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
4376 {
4377 /* VectorHeightSmaller Penalty 2 */
4378 /* Candidate is a vector font that is smaller than the
4379 requested height. Penalty * height difference */
4380 Penalty += 2 * labs(TM->tmHeight - LogFont->lfHeight);
4381 }
4382 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
4383 {
4384 /* VectorHeightBigger Penalty 1 */
4385 /* Candidate is a vector font that is bigger than the
4386 requested height. Penalty * height difference */
4387 Penalty += 1 * labs(TM->tmHeight - LogFont->lfHeight);
4388 }
4389 }
4390
4391 if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
4392 {
4393 /* DeviceFavor Penalty 2 */
4394 /* Extra penalty for all nondevice fonts. */
4395 Penalty += 2;
4396 }
4397
4398 if (Penalty < 200)
4399 {
4400 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
4401 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
4402 "tmCharSet:%d, tmWeight:%ld\n",
4403 Penalty, LogFont->lfFaceName, ActualNameW,
4404 LogFont->lfCharSet, LogFont->lfWeight,
4405 TM->tmCharSet, TM->tmWeight);
4406 }
4407
4408 return Penalty; /* success */
4409 }
4410
4411 static __inline VOID
4412 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
4413 const LOGFONTW *LogFont,
4414 const PLIST_ENTRY Head)
4415 {
4416 ULONG Penalty;
4417 PLIST_ENTRY Entry;
4418 PFONT_ENTRY CurrentEntry;
4419 FONTGDI *FontGDI;
4420 OUTLINETEXTMETRICW *Otm = NULL;
4421 UINT OtmSize, OldOtmSize = 0;
4422 FT_Face Face;
4423
4424 ASSERT(FontObj);
4425 ASSERT(MatchPenalty);
4426 ASSERT(LogFont);
4427 ASSERT(Head);
4428
4429 /* Start with a pretty big buffer */
4430 OldOtmSize = 0x200;
4431 Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
4432
4433 /* get the FontObj of lowest penalty */
4434 Entry = Head->Flink;
4435 while (Entry != Head)
4436 {
4437 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
4438 Entry = Entry->Flink;
4439
4440 FontGDI = CurrentEntry->Font;
4441 ASSERT(FontGDI);
4442 Face = FontGDI->SharedFace->Face;
4443
4444 /* get text metrics */
4445 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4446 if (OtmSize > OldOtmSize)
4447 {
4448 if (Otm)
4449 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4450 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
4451 }
4452
4453 /* update FontObj if lowest penalty */
4454 if (Otm)
4455 {
4456 OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
4457 if (!OtmSize)
4458 continue;
4459
4460 OldOtmSize = OtmSize;
4461
4462 Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
4463 if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
4464 {
4465 *FontObj = GDIToObj(FontGDI, FONT);
4466 *MatchPenalty = Penalty;
4467 }
4468 }
4469 }
4470
4471 if (Otm)
4472 ExFreePoolWithTag(Otm, GDITAG_TEXT);
4473 }
4474
4475 static
4476 VOID
4477 FASTCALL
4478 IntFontType(PFONTGDI Font)
4479 {
4480 PS_FontInfoRec psfInfo;
4481 FT_ULong tmp_size = 0;
4482 FT_Face Face = Font->SharedFace->Face;
4483
4484 if (FT_HAS_MULTIPLE_MASTERS(Face))
4485 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
4486 if (FT_HAS_VERTICAL(Face))
4487 Font->FontObj.flFontType |= FO_VERT_FACE;
4488 if (!FT_IS_SCALABLE(Face))
4489 Font->FontObj.flFontType |= FO_TYPE_RASTER;
4490 if (FT_IS_SFNT(Face))
4491 {
4492 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
4493 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
4494 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4495 }
4496 if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
4497 {
4498 Font->FontObj.flFontType |= FO_POSTSCRIPT;
4499 }
4500 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
4501 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
4502 {
4503 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
4504 }
4505 }
4506
4507 NTSTATUS
4508 FASTCALL
4509 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
4510 {
4511 NTSTATUS Status = STATUS_SUCCESS;
4512 PTEXTOBJ TextObj;
4513 PPROCESSINFO Win32Process;
4514 ULONG MatchPenalty;
4515 LOGFONTW *pLogFont;
4516 LOGFONTW SubstitutedLogFont;
4517 FT_Face Face;
4518
4519 if (!pTextObj)
4520 {
4521 TextObj = TEXTOBJ_LockText(FontHandle);
4522 if (NULL == TextObj)
4523 {
4524 return STATUS_INVALID_HANDLE;
4525 }
4526
4527 if (TextObj->fl & TEXTOBJECT_INIT)
4528 {
4529 TEXTOBJ_UnlockText(TextObj);
4530 return STATUS_SUCCESS;
4531 }
4532 }
4533 else
4534 {
4535 TextObj = pTextObj;
4536 }
4537
4538 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4539
4540 /* substitute */
4541 SubstitutedLogFont = *pLogFont;
4542 DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
4543 SubstituteFontRecurse(&SubstitutedLogFont);
4544 DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
4545
4546 MatchPenalty = 0xFFFFFFFF;
4547 TextObj->Font = NULL;
4548
4549 Win32Process = PsGetCurrentProcessWin32Process();
4550
4551 /* Search private fonts */
4552 IntLockProcessPrivateFonts(Win32Process);
4553 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4554 &Win32Process->PrivateFontListHead);
4555 IntUnLockProcessPrivateFonts(Win32Process);
4556
4557 /* Search system fonts */
4558 IntLockGlobalFonts;
4559 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
4560 &FontListHead);
4561 IntUnLockGlobalFonts;
4562
4563 if (NULL == TextObj->Font)
4564 {
4565 DPRINT1("Request font %S not found, no fonts loaded at all\n",
4566 pLogFont->lfFaceName);
4567 Status = STATUS_NOT_FOUND;
4568 }
4569 else
4570 {
4571 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
4572 // Need hdev, when freetype is loaded need to create DEVOBJ for
4573 // Consumer and Producer.
4574 TextObj->Font->iUniq = 1; // Now it can be cached.
4575 IntFontType(FontGdi);
4576 FontGdi->flType = TextObj->Font->flFontType;
4577 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
4578 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
4579 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
4580 if (pLogFont->lfWeight != FW_DONTCARE)
4581 FontGdi->RequestWeight = pLogFont->lfWeight;
4582 else
4583 FontGdi->RequestWeight = FW_NORMAL;
4584
4585 Face = FontGdi->SharedFace->Face;
4586
4587 //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name);
4588
4589 if (!FontGdi->OriginalItalic)
4590 FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name);
4591
4592 TextObj->fl |= TEXTOBJECT_INIT;
4593 Status = STATUS_SUCCESS;
4594 }
4595
4596 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
4597
4598 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
4599
4600 return Status;
4601 }
4602
4603
4604 static
4605 BOOL
4606 FASTCALL
4607 IntGetFullFileName(
4608 POBJECT_NAME_INFORMATION NameInfo,
4609 ULONG Size,
4610 PUNICODE_STRING FileName)
4611 {
4612 NTSTATUS Status;
4613 OBJECT_ATTRIBUTES ObjectAttributes;
4614 HANDLE hFile;
4615 IO_STATUS_BLOCK IoStatusBlock;
4616 ULONG Desired;
4617
4618 InitializeObjectAttributes(&ObjectAttributes,
4619 FileName,
4620 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
4621 NULL,
4622 NULL);
4623
4624 Status = ZwOpenFile(
4625 &hFile,
4626 0, // FILE_READ_ATTRIBUTES,
4627 &ObjectAttributes,
4628 &IoStatusBlock,
4629 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4630 0);
4631
4632 if (!NT_SUCCESS(Status))
4633 {
4634 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
4635 return FALSE;
4636 }
4637
4638 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
4639 ZwClose(hFile);
4640 if (!NT_SUCCESS(Status))
4641 {
4642 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
4643 return FALSE;
4644 }
4645
4646 return TRUE;
4647 }
4648
4649 static BOOL
4650 EqualFamilyInfo(FONTFAMILYINFO *pInfo1, FONTFAMILYINFO *pInfo2)
4651 {
4652 UNICODE_STRING Str1, Str2;
4653 ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
4654 ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
4655 RtlInitUnicodeString(&Str1, pLog1->elfLogFont.lfFaceName);
4656 RtlInitUnicodeString(&Str2, pLog2->elfLogFont.lfFaceName);
4657 if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE))
4658 {
4659 return FALSE;
4660 }
4661 if ((pLog1->elfStyle != NULL) != (pLog2->elfStyle != NULL))
4662 return FALSE;
4663 if (pLog1->elfStyle != NULL)
4664 {
4665 RtlInitUnicodeString(&Str1, pLog1->elfStyle);
4666 RtlInitUnicodeString(&Str2, pLog2->elfStyle);
4667 if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE))
4668 {
4669 return FALSE;
4670 }
4671 }
4672 return TRUE;
4673 }
4674
4675 static VOID
4676 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
4677 {
4678 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
4679 if (FamInfo->EnumLogFontEx.elfStyle[0] &&
4680 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
4681 {
4682 wcscat(psz, L" ");
4683 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
4684 }
4685 }
4686
4687 BOOL
4688 FASTCALL
4689 IntGdiGetFontResourceInfo(
4690 PUNICODE_STRING FileName,
4691 PVOID pBuffer,
4692 DWORD *pdwBytes,
4693 DWORD dwType)
4694 {
4695 UNICODE_STRING EntryFileName;
4696 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
4697 PLIST_ENTRY ListEntry;
4698 PFONT_ENTRY FontEntry;
4699 ULONG Size, i, Count;
4700 LPBYTE pbBuffer;
4701 BOOL IsEqual;
4702 FONTFAMILYINFO *FamInfo;
4703 const ULONG MaxFamInfo = 64;
4704 BOOL bSuccess;
4705
4706 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
4707
4708 /* Create buffer for full path name */
4709 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
4710 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4711 if (!NameInfo1)
4712 {
4713 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4714 return FALSE;
4715 }
4716
4717 /* Get the full path name */
4718 if (!IntGetFullFileName(NameInfo1, Size, FileName))
4719 {
4720 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4721 return FALSE;
4722 }
4723
4724 /* Create a buffer for the entries' names */
4725 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4726 if (!NameInfo2)
4727 {
4728 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4729 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4730 return FALSE;
4731 }
4732
4733 FamInfo = ExAllocatePoolWithTag(PagedPool,
4734 sizeof(FONTFAMILYINFO) * MaxFamInfo,
4735 TAG_FINF);
4736 if (!FamInfo)
4737 {
4738 ExFreePoolWithTag(NameInfo2, TAG_FINF);
4739 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4740 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4741 return FALSE;
4742 }
4743 /* Try to find the pathname in the global font list */
4744 Count = 0;
4745 IntLockGlobalFonts;
4746 for (ListEntry = FontListHead.Flink; ListEntry != &FontListHead;
4747 ListEntry = ListEntry->Flink)
4748 {
4749 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
4750 if (FontEntry->Font->Filename == NULL)
4751 continue;
4752
4753 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
4754 if (!IntGetFullFileName(NameInfo2, Size, &EntryFileName))
4755 continue;
4756
4757 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
4758 continue;
4759
4760 IsEqual = FALSE;
4761 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
4762 NULL, FontEntry->Font);
4763 for (i = 0; i < Count; ++i)
4764 {
4765 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
4766 {
4767 IsEqual = TRUE;
4768 break;
4769 }
4770 }
4771 if (!IsEqual)
4772 {
4773 /* Found */
4774 ++Count;
4775 if (Count >= MaxFamInfo)
4776 break;
4777 }
4778 }
4779 IntUnLockGlobalFonts;
4780
4781 /* Free the buffers */
4782 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4783 ExFreePool(NameInfo2);
4784
4785 if (Count == 0 && dwType != 5)
4786 {
4787 /* Font could not be found in system table
4788 dwType == 5 will still handle this */
4789 ExFreePoolWithTag(FamInfo, TAG_FINF);
4790 return FALSE;
4791 }
4792
4793 bSuccess = FALSE;
4794 switch (dwType)
4795 {
4796 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
4797 Size = sizeof(DWORD);
4798 if (*pdwBytes == 0)
4799 {
4800 *pdwBytes = Size;
4801 bSuccess = TRUE;
4802 }
4803 else if (pBuffer)
4804 {
4805 if (*pdwBytes >= Size)
4806 {
4807 *(DWORD*)pBuffer = Count;
4808 }
4809 *pdwBytes = Size;
4810 bSuccess = TRUE;
4811 }
4812 break;
4813
4814 case 1: /* copy the font title */
4815 /* calculate the required size */
4816 Size = 0;
4817 Size += wcslen(FamInfo[0].EnumLogFontEx.elfLogFont.lfFaceName);
4818 if (FamInfo[0].EnumLogFontEx.elfStyle[0] &&
4819 _wcsicmp(FamInfo[0].EnumLogFontEx.elfStyle, L"Regular") != 0)
4820 {
4821 Size += 1 + wcslen(FamInfo[0].EnumLogFontEx.elfStyle);
4822 }
4823 for (i = 1; i < Count; ++i)
4824 {
4825 Size += 3; /* " & " */
4826 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
4827 if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
4828 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
4829 {
4830 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
4831 }
4832 }
4833 Size += 2; /* "\0\0" */
4834 Size *= sizeof(WCHAR);
4835
4836 if (*pdwBytes == 0)
4837 {
4838 *pdwBytes = Size;
4839 bSuccess = TRUE;
4840 }
4841 else if (pBuffer)
4842 {
4843 if (*pdwBytes >= Size)
4844 {
4845 /* store font title to buffer */
4846 WCHAR *psz = pBuffer;
4847 *psz = 0;
4848 IntAddNameFromFamInfo(psz, &FamInfo[0]);
4849 for (i = 1; i < Count; ++i)
4850 {
4851 wcscat(psz, L" & ");
4852 IntAddNameFromFamInfo(psz, &FamInfo[i]);
4853 }
4854 psz[wcslen(psz) + 1] = UNICODE_NULL;
4855 *pdwBytes = Size;
4856 bSuccess = TRUE;
4857 }
4858 else
4859 {
4860 *pdwBytes = 1024; /* this is confirmed value */
4861 }
4862 }
4863 break;
4864
4865 case 2: /* Copy an array of LOGFONTW */
4866 Size = Count * sizeof(LOGFONTW);
4867 if (*pdwBytes == 0)
4868 {
4869 *pdwBytes = Size;
4870 bSuccess = TRUE;
4871 }
4872 else if (pBuffer)
4873 {
4874 if (*pdwBytes >= Size)
4875 {
4876 pbBuffer = (LPBYTE)pBuffer;
4877 for (i = 0; i < Count; ++i)
4878 {
4879 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
4880 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
4881 pbBuffer += sizeof(LOGFONTW);
4882 }
4883 }
4884 *pdwBytes = Size;
4885 bSuccess = TRUE;
4886 }
4887 else
4888 {
4889 *pdwBytes = 1024; /* this is confirmed value */
4890 }
4891 break;
4892
4893 case 3:
4894 Size = sizeof(DWORD);
4895 if (*pdwBytes == 0)
4896 {
4897 *pdwBytes = Size;
4898 bSuccess = TRUE;
4899 }
4900 else if (pBuffer)
4901 {
4902 if (*pdwBytes >= Size)
4903 {
4904 /* FIXME: What exactly is copied here? */
4905 *(DWORD*)pBuffer = 1;
4906 }
4907 *pdwBytes = Size;
4908 bSuccess = TRUE;
4909 }
4910 break;
4911
4912 case 4: /* full file path */
4913 if (FileName->Length >= 4 * sizeof(WCHAR))
4914 {
4915 /* The beginning of FileName is \??\ */
4916 LPWSTR pch = FileName->Buffer + 4;
4917 DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
4918
4919 Size = Length + sizeof(WCHAR);
4920 if (*pdwBytes == 0)
4921 {
4922 *pdwBytes = Size;
4923 bSuccess = TRUE;
4924 }
4925 else if (pBuffer)
4926 {
4927 if (*pdwBytes >= Size)
4928 {
4929 RtlCopyMemory(pBuffer, pch, Size);
4930 }
4931 *pdwBytes = Size;
4932 bSuccess = TRUE;
4933 }
4934 }
4935 break;
4936
4937 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
4938 Size = sizeof(BOOL);
4939 if (*pdwBytes == 0)
4940 {
4941 *pdwBytes = Size;
4942 bSuccess = TRUE;
4943 }
4944 else if (pBuffer)
4945 {
4946 if (*pdwBytes >= Size)
4947 {
4948 *(BOOL*)pBuffer = Count == 0;
4949 }
4950 *pdwBytes = Size;
4951 bSuccess = TRUE;
4952 }
4953 break;
4954 }
4955 ExFreePoolWithTag(FamInfo, TAG_FINF);
4956
4957 return bSuccess;
4958 }
4959
4960
4961 BOOL
4962 FASTCALL
4963 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
4964 {
4965 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
4966 Info->iTechnology = RI_TECH_BITMAP;
4967 else
4968 {
4969 if (FT_IS_SCALABLE(Font->SharedFace->Face))
4970 Info->iTechnology = RI_TECH_SCALABLE;
4971 else
4972 Info->iTechnology = RI_TECH_FIXED;
4973 }
4974 Info->iUniq = Font->FontObj.iUniq;
4975 Info->dwUnknown = -1;
4976 return TRUE;
4977 }
4978
4979
4980 DWORD
4981 FASTCALL
4982 ftGdiGetKerningPairs( PFONTGDI Font,
4983 DWORD cPairs,
4984 LPKERNINGPAIR pKerningPair)
4985 {
4986 DWORD Count = 0;
4987 INT i = 0;
4988 FT_Face face = Font->SharedFace->Face;
4989
4990 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
4991 {
4992 FT_UInt previous_index = 0, glyph_index = 0;
4993 FT_ULong char_code, char_previous;
4994 FT_Vector delta;
4995
4996 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
4997
4998 IntLockFreeType;
4999
5000 while (glyph_index)
5001 {
5002 if (previous_index && glyph_index)
5003 {
5004 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
5005
5006 if (pKerningPair && cPairs)
5007 {
5008 pKerningPair[i].wFirst = char_previous;
5009 pKerningPair[i].wSecond = char_code;
5010 pKerningPair[i].iKernAmount = delta.x;
5011 i++;
5012 if (i == cPairs) break;
5013 }
5014 Count++;
5015 }
5016 previous_index = glyph_index;
5017 char_previous = char_code;
5018 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
5019 }
5020 IntUnLockFreeType;
5021 }
5022 return Count;
5023 }
5024
5025
5026 ///////////////////////////////////////////////////////////////////////////
5027 //
5028 // Functions needing sorting.
5029 //
5030 ///////////////////////////////////////////////////////////////////////////
5031 int APIENTRY
5032 NtGdiGetFontFamilyInfo(HDC Dc,
5033 LPLOGFONTW UnsafeLogFont,
5034 PFONTFAMILYINFO UnsafeInfo,
5035 DWORD Size)
5036 {
5037 NTSTATUS Status;
5038 LOGFONTW LogFont;
5039 PFONTFAMILYINFO Info;
5040 DWORD Count;
5041 PPROCESSINFO Win32Process;
5042
5043 /* Make a safe copy */
5044 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
5045 if (! NT_SUCCESS(Status))
5046 {
5047 EngSetLastError(ERROR_INVALID_PARAMETER);
5048 return -1;
5049 }
5050
5051 /* Allocate space for a safe copy */
5052 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT);
5053 if (NULL == Info)
5054 {
5055 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5056 return -1;
5057 }
5058
5059 /* Enumerate font families in the global list */
5060 IntLockGlobalFonts;
5061 Count = 0;
5062 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
5063 {
5064 IntUnLockGlobalFonts;
5065 ExFreePoolWithTag(Info, GDITAG_TEXT);
5066 return -1;
5067 }
5068 IntUnLockGlobalFonts;
5069
5070 /* Enumerate font families in the process local list */
5071 Win32Process = PsGetCurrentProcessWin32Process();
5072 IntLockProcessPrivateFonts(Win32Process);
5073 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
5074 &Win32Process->PrivateFontListHead))
5075 {
5076 IntUnLockProcessPrivateFonts(Win32Process);
5077 ExFreePoolWithTag(Info, GDITAG_TEXT);
5078 return -1;
5079 }
5080 IntUnLockProcessPrivateFonts(Win32Process);
5081
5082 /* Enumerate font families in the registry */
5083 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
5084 {
5085 ExFreePoolWithTag(Info, GDITAG_TEXT);
5086 return -1;
5087 }
5088
5089 /* Return data to caller */
5090 if (0 != Count)
5091 {
5092 Status = MmCopyToCaller(UnsafeInfo, Info,
5093 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
5094 if (! NT_SUCCESS(Status))
5095 {
5096 ExFreePoolWithTag(Info, GDITAG_TEXT);
5097 EngSetLastError(ERROR_INVALID_PARAMETER);
5098 return -1;
5099 }
5100 }
5101
5102 ExFreePoolWithTag(Info, GDITAG_TEXT);
5103
5104 return Count;
5105 }
5106
5107 FORCEINLINE
5108 LONG
5109 ScaleLong(LONG lValue, PFLOATOBJ pef)
5110 {
5111 FLOATOBJ efTemp;
5112
5113 /* Check if we have scaling different from 1 */
5114 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
5115 {
5116 /* Need to multiply */
5117 FLOATOBJ_SetLong(&efTemp, lValue);
5118 FLOATOBJ_Mul(&efTemp, pef);
5119 lValue = FLOATOBJ_GetLong(&efTemp);
5120 }
5121
5122 return lValue;
5123 }
5124
5125 BOOL
5126 APIENTRY
5127 GreExtTextOutW(
5128 IN HDC hDC,
5129 IN INT XStart,
5130 IN INT YStart,
5131 IN UINT fuOptions,
5132 IN OPTIONAL PRECTL lprc,
5133 IN LPCWSTR String,
5134 IN INT Count,
5135 IN OPTIONAL LPINT Dx,
5136 IN DWORD dwCodePage)
5137 {
5138 /*
5139 * FIXME:
5140 * Call EngTextOut, which does the real work (calling DrvTextOut where
5141 * appropriate)
5142 */
5143
5144 DC *dc;
5145 PDC_ATTR pdcattr;
5146 SURFOBJ *SurfObj;
5147 SURFACE *psurf = NULL;
5148 int error, glyph_index, i;
5149 FT_Face face;
5150 FT_GlyphSlot glyph;
5151 FT_BitmapGlyph realglyph;
5152 LONGLONG TextLeft, RealXStart;
5153 ULONG TextTop, previous, BackgroundLeft;
5154 FT_Bool use_kerning;
5155 RECTL DestRect, MaskRect;
5156 POINTL SourcePoint, BrushOrigin;
5157 HBITMAP HSourceGlyph;
5158 SURFOBJ *SourceGlyphSurf;
5159 SIZEL bitSize;
5160 INT yoff;
5161 FONTOBJ *FontObj;
5162 PFONTGDI FontGDI;
5163 PTEXTOBJ TextObj = NULL;
5164 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
5165 FT_Render_Mode RenderMode;
5166 BOOLEAN Render;
5167 POINT Start;
5168 BOOL DoBreak = FALSE;
5169 USHORT DxShift;
5170 PMATRIX pmxWorldToDevice;
5171 LONG fixAscender, fixDescender;
5172 FLOATOBJ Scale;
5173 LOGFONTW *plf;
5174 BOOL EmuBold, EmuItalic;
5175 int thickness;
5176
5177 // TODO: Write test-cases to exactly match real Windows in different
5178 // bad parameters (e.g. does Windows check the DC or the RECT first?).
5179 dc = DC_LockDc(hDC);
5180 if (!dc)
5181 {
5182 EngSetLastError(ERROR_INVALID_HANDLE);
5183 return FALSE;
5184 }
5185 if (dc->dctype == DC_TYPE_INFO)
5186 {
5187 DC_UnlockDc(dc);
5188 /* Yes, Windows really returns TRUE in this case */
5189 return TRUE;
5190 }
5191
5192 pdcattr = dc->pdcattr;
5193
5194 if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE)
5195 {
5196 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5197 DC_vUpdateBackgroundBrush(dc);
5198 }
5199
5200 /* Check if String is valid */
5201 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
5202 {
5203 EngSetLastError(ERROR_INVALID_PARAMETER);
5204 goto fail;
5205 }
5206
5207 DxShift = fuOptions & ETO_PDY ? 1 : 0;
5208
5209 if (PATH_IsPathOpen(dc->dclevel))
5210 {
5211 if (!PATH_ExtTextOut( dc,
5212 XStart,
5213 YStart,
5214 fuOptions,
5215 (const RECTL *)lprc,
5216 String,
5217 Count,
5218 (const INT *)Dx)) goto fail;
5219 goto good;
5220 }
5221
5222 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
5223 {
5224 IntLPtoDP(dc, (POINT *)lprc, 2);
5225 }
5226
5227 if (pdcattr->lTextAlign & TA_UPDATECP)
5228 {
5229 Start.x = pdcattr->ptlCurrent.x;
5230 Start.y = pdcattr->ptlCurrent.y;
5231 } else {
5232 Start.x = XStart;
5233 Start.y = YStart;
5234 }
5235
5236 IntLPtoDP(dc, &Start, 1);
5237 RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
5238 YStart = Start.y + dc->ptlDCOrig.y;
5239
5240 SourcePoint.x = 0;
5241 SourcePoint.y = 0;
5242 MaskRect.left = 0;
5243 MaskRect.top = 0;
5244 BrushOrigin.x = 0;
5245 BrushOrigin.y = 0;
5246
5247 if (!dc->dclevel.pSurface)
5248 {
5249 goto fail;
5250 }
5251
5252 if ((fuOptions & ETO_OPAQUE) && lprc)
5253 {
5254 DestRect.left = lprc->left;
5255 DestRect.top = lprc->top;
5256 DestRect.right = lprc->right;
5257 DestRect.bottom = lprc->bottom;
5258
5259 DestRect.left += dc->ptlDCOrig.x;
5260 DestRect.top += dc->ptlDCOrig.y;
5261 DestRect.right += dc->ptlDCOrig.x;
5262 DestRect.bottom += dc->ptlDCOrig.y;
5263
5264 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5265 {
5266 IntUpdateBoundsRect(dc, &DestRect);
5267 }
5268
5269 DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL);
5270
5271 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
5272 DC_vUpdateBackgroundBrush(dc);
5273
5274 psurf = dc->dclevel.pSurface;
5275 IntEngBitBlt(
5276 &psurf->SurfObj,
5277 NULL,
5278 NULL,
5279 &dc->co.ClipObj,
5280 NULL,
5281 &DestRect,
5282 &SourcePoint,
5283 &SourcePoint,
5284 &dc->eboBackground.BrushObject,
5285 &BrushOrigin,
5286 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5287 fuOptions &= ~ETO_OPAQUE;
5288 DC_vFinishBlit(dc, NULL);
5289 }
5290 else
5291 {
5292 if (pdcattr->jBkMode == OPAQUE)
5293 {
5294 fuOptions |= ETO_OPAQUE;
5295 }
5296 }
5297
5298 TextObj = RealizeFontInit(pdcattr->hlfntNew);
5299 if (TextObj == NULL)
5300 {
5301 goto fail;
5302 }
5303
5304 FontObj = TextObj->Font;
5305 ASSERT(FontObj);
5306 FontGDI = ObjToGDI(FontObj, FONT);
5307 ASSERT(FontGDI);
5308
5309 IntLockFreeType;
5310 face = FontGDI->SharedFace->Face;
5311
5312 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5313 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
5314 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
5315
5316 Render = IntIsFontRenderingEnabled();
5317 if (Render)
5318 RenderMode = IntGetFontRenderMode(plf);
5319 else
5320 RenderMode = FT_RENDER_MODE_MONO;
5321
5322 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
5323 {
5324 IntUnLockFreeType;
5325 goto fail;
5326 }
5327
5328 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
5329 {
5330 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
5331 FtSetCoordinateTransform(face, pmxWorldToDevice);
5332
5333 fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
5334 fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
5335 }
5336 else
5337 {
5338 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
5339 FtSetCoordinateTransform(face, pmxWorldToDevice);
5340
5341 fixAscender = face->size->metrics.ascender;
5342 fixDescender = face->size->metrics.descender;
5343 }
5344
5345 /*
5346 * Process the vertical alignment and determine the yoff.
5347 */
5348
5349 if (pdcattr->lTextAlign & TA_BASELINE)
5350 yoff = 0;
5351 else if (pdcattr->lTextAlign & TA_BOTTOM)
5352 yoff = -fixDescender >> 6;
5353 else /* TA_TOP */
5354 yoff = fixAscender >> 6;
5355
5356 use_kerning = FT_HAS_KERNING(face);
5357 previous = 0;
5358
5359 /*
5360 * Process the horizontal alignment and modify XStart accordingly.
5361 */
5362
5363 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
5364 {
5365 ULONGLONG TextWidth = 0;
5366 LPCWSTR TempText = String;
5367 int iStart;
5368
5369 /*
5370 * Calculate width of the text.
5371 */
5372
5373 if (NULL != Dx)
5374 {
5375 iStart = Count < 2 ? 0 : Count - 2;
5376 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
5377 }
5378 else
5379 {
5380 iStart = 0;
5381 }
5382 TempText = String + iStart;
5383
5384 for (i = iStart; i < Count; i++)
5385 {
5386 if (fuOptions & ETO_GLYPH_INDEX)
5387 glyph_index = *TempText;
5388 else
5389 glyph_index = FT_Get_Char_Index(face, *TempText);
5390
5391 if (EmuBold || EmuItalic)
5392 realglyph = NULL;
5393 else
5394 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
5395 plf->lfHeight, pmxWorldToDevice);
5396 if (!realglyph)
5397 {
5398 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5399 if (error)
5400 {
5401 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
5402 }
5403
5404 glyph = face->glyph;
5405 if (EmuBold || EmuItalic)
5406 {
5407 if (EmuBold)
5408 FT_GlyphSlot_Embolden(glyph);
5409 if (EmuItalic)
5410 FT_GlyphSlot_Oblique(glyph);
5411 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5412 }
5413 else
5414 {
5415 realglyph = ftGdiGlyphCacheSet(face,
5416 glyph_index,
5417 plf->lfHeight,
5418 pmxWorldToDevice,
5419 glyph,
5420 RenderMode);
5421 }
5422 if (!realglyph)
5423 {
5424 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5425 IntUnLockFreeType;
5426 goto fail;
5427 }
5428
5429 }
5430 /* Retrieve kerning distance */
5431 if (use_kerning && previous && glyph_index)
5432 {
5433 FT_Vector delta;
5434 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5435 TextWidth += delta.x;
5436 }
5437
5438 TextWidth += realglyph->root.advance.x >> 10;
5439
5440 if (EmuBold || EmuItalic)
5441 {
5442 FT_Done_Glyph((FT_Glyph)realglyph);
5443 realglyph = NULL;
5444 }
5445
5446 previous = glyph_index;
5447 TempText++;
5448 }
5449
5450 previous = 0;
5451
5452 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
5453 {
5454 RealXStart -= TextWidth / 2;
5455 }
5456 else
5457 {
5458 RealXStart -= TextWidth;
5459 }
5460 }
5461
5462 /* Lock blit with a dummy rect */
5463 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
5464
5465 psurf = dc->dclevel.pSurface;
5466 SurfObj = &psurf->SurfObj ;
5467
5468 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
5469 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
5470
5471 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
5472 DC_vUpdateBackgroundBrush(dc) ;
5473
5474 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
5475 DC_vUpdateTextBrush(dc) ;
5476
5477 if (!face->units_per_EM)
5478 {
5479 thickness = 1;
5480 }
5481 else
5482 {
5483 thickness = face->underline_thickness *
5484 face->size->metrics.y_ppem / face->units_per_EM;
5485 if (thickness <= 0)
5486 thickness = 1;
5487 }
5488
5489 if ((fuOptions & ETO_OPAQUE) && plf->lfItalic)
5490 {
5491 /* Draw background */
5492 TextLeft = RealXStart;
5493 TextTop = YStart;
5494 BackgroundLeft = (RealXStart + 32) >> 6;
5495 for (i = 0; i < Count; ++i)
5496 {
5497 if (fuOptions & ETO_GLYPH_INDEX)
5498 glyph_index = String[i];
5499 else
5500 glyph_index = FT_Get_Char_Index(face, String[i]);
5501
5502 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5503 if (error)
5504 {
5505 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5506 IntUnLockFreeType;
5507 DC_vFinishBlit(dc, NULL);
5508 goto fail2;
5509 }
5510
5511 glyph = face->glyph;
5512 if (EmuBold)
5513 FT_GlyphSlot_Embolden(glyph);
5514 if (EmuItalic)
5515 FT_GlyphSlot_Oblique(glyph);
5516 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5517 if (!realglyph)
5518 {
5519 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5520 IntUnLockFreeType;
5521 DC_vFinishBlit(dc, NULL);
5522 goto fail2;
5523 }
5524
5525 /* retrieve kerning distance and move pen position */
5526 if (use_kerning && previous && glyph_index && NULL == Dx)
5527 {
5528 FT_Vector delta;
5529 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5530 TextLeft += delta.x;
5531 }
5532 DPRINT("TextLeft: %I64d\n", TextLeft);
5533 DPRINT("TextTop: %lu\n", TextTop);
5534 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5535
5536 DestRect.left = BackgroundLeft;
5537 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5538 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5539 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5540 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5541 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5542 {
5543 IntUpdateBoundsRect(dc, &DestRect);
5544 }
5545 IntEngBitBlt(
5546 &psurf->SurfObj,
5547 NULL,
5548 NULL,
5549 &dc->co.ClipObj,
5550 NULL,
5551 &DestRect,
5552 &SourcePoint,
5553 &SourcePoint,
5554 &dc->eboBackground.BrushObject,
5555 &BrushOrigin,
5556 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5557 MouseSafetyOnDrawEnd(dc->ppdev);
5558 BackgroundLeft = DestRect.right;
5559
5560 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5561 DestRect.right = DestRect.left + realglyph->bitmap.width;
5562 DestRect.top = TextTop + yoff - realglyph->top;
5563 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5564
5565 bitSize.cx = realglyph->bitmap.width;
5566 bitSize.cy = realglyph->bitmap.rows;
5567 MaskRect.right = realglyph->bitmap.width;
5568 MaskRect.bottom = realglyph->bitmap.rows;
5569
5570 if (NULL == Dx)
5571 {
5572 TextLeft += realglyph->root.advance.x >> 10;
5573 DPRINT("New TextLeft: %I64d\n", TextLeft);
5574 }
5575 else
5576 {
5577 // FIXME this should probably be a matrix transform with TextTop as well.
5578 Scale = pdcattr->mxWorldToDevice.efM11;
5579 if (FLOATOBJ_Equal0(&Scale))
5580 FLOATOBJ_Set1(&Scale);
5581
5582 /* do the shift before multiplying to preserve precision */
5583 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5584 TextLeft += FLOATOBJ_GetLong(&Scale);
5585 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5586 }
5587
5588 if (DxShift)
5589 {
5590 TextTop -= Dx[2 * i + 1] << 6;
5591 }
5592
5593 previous = glyph_index;
5594
5595 if (EmuBold || EmuItalic)
5596 {
5597 FT_Done_Glyph((FT_Glyph)realglyph);
5598 realglyph = NULL;
5599 }
5600 }
5601 }
5602
5603 /*
5604 * The main rendering loop.
5605 */
5606 TextLeft = RealXStart;
5607 TextTop = YStart;
5608 BackgroundLeft = (RealXStart + 32) >> 6;
5609 for (i = 0; i < Count; ++i)
5610 {
5611 if (fuOptions & ETO_GLYPH_INDEX)
5612 glyph_index = String[i];
5613 else
5614 glyph_index = FT_Get_Char_Index(face, String[i]);
5615
5616 if (EmuBold || EmuItalic)
5617 realglyph = NULL;
5618 else
5619 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
5620 plf->lfHeight, pmxWorldToDevice);
5621 if (!realglyph)
5622 {
5623 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5624 if (error)
5625 {
5626 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5627 IntUnLockFreeType;
5628 DC_vFinishBlit(dc, NULL);
5629 goto fail2;
5630 }
5631
5632 glyph = face->glyph;
5633 if (EmuBold || EmuItalic)
5634 {
5635 if (EmuBold)
5636 FT_GlyphSlot_Embolden(glyph);
5637 if (EmuItalic)
5638 FT_GlyphSlot_Oblique(glyph);
5639 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5640 }
5641 else
5642 {
5643 realglyph = ftGdiGlyphCacheSet(face,
5644 glyph_index,
5645 plf->lfHeight,
5646 pmxWorldToDevice,
5647 glyph,
5648 RenderMode);
5649 }
5650 if (!realglyph)
5651 {
5652 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5653 IntUnLockFreeType;
5654 DC_vFinishBlit(dc, NULL);
5655 goto fail2;
5656 }
5657 }
5658
5659 /* retrieve kerning distance and move pen position */
5660 if (use_kerning && previous && glyph_index && NULL == Dx)
5661 {
5662 FT_Vector delta;
5663 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5664 TextLeft += delta.x;
5665 }
5666 DPRINT("TextLeft: %I64d\n", TextLeft);
5667 DPRINT("TextTop: %lu\n", TextTop);
5668 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5669
5670 if ((fuOptions & ETO_OPAQUE) && !plf->lfItalic)
5671 {
5672 DestRect.left = BackgroundLeft;
5673 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5674 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5675 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5676 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5677 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5678 {
5679 IntUpdateBoundsRect(dc, &DestRect);
5680 }
5681 IntEngBitBlt(
5682 &psurf->SurfObj,
5683 NULL,
5684 NULL,
5685 &dc->co.ClipObj,
5686 NULL,
5687 &DestRect,
5688 &SourcePoint,
5689 &SourcePoint,
5690 &dc->eboBackground.BrushObject,
5691 &BrushOrigin,
5692 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5693 MouseSafetyOnDrawEnd(dc->ppdev);
5694 BackgroundLeft = DestRect.right;
5695 }
5696
5697 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5698 DestRect.right = DestRect.left + realglyph->bitmap.width;
5699 DestRect.top = TextTop + yoff - realglyph->top;
5700 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5701
5702 bitSize.cx = realglyph->bitmap.width;
5703 bitSize.cy = realglyph->bitmap.rows;
5704 MaskRect.right = realglyph->bitmap.width;
5705 MaskRect.bottom = realglyph->bitmap.rows;
5706
5707 /* Check if the bitmap has any pixels */
5708 if ((bitSize.cx != 0) && (bitSize.cy != 0))
5709 {
5710 /*
5711 * We should create the bitmap out of the loop at the biggest possible
5712 * glyph size. Then use memset with 0 to clear it and sourcerect to
5713 * limit the work of the transbitblt.
5714 */
5715 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
5716 BMF_8BPP, BMF_TOPDOWN,
5717 realglyph->bitmap.buffer);
5718 if ( !HSourceGlyph )
5719 {
5720 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
5721 // FT_Done_Glyph(realglyph);
5722 IntUnLockFreeType;
5723 DC_vFinishBlit(dc, NULL);
5724 goto fail2;
5725 }
5726 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
5727 if ( !SourceGlyphSurf )
5728 {
5729 EngDeleteSurface((HSURF)HSourceGlyph);
5730 DPRINT1("WARNING: EngLockSurface() failed!\n");
5731 IntUnLockFreeType;
5732 DC_vFinishBlit(dc, NULL);
5733 goto fail2;
5734 }
5735
5736 /*
5737 * Use the font data as a mask to paint onto the DCs surface using a
5738 * brush.
5739 */
5740 if (lprc && (fuOptions & ETO_CLIPPED) &&
5741 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
5742 {
5743 // We do the check '>=' instead of '>' to possibly save an iteration
5744 // through this loop, since it's breaking after the drawing is done,
5745 // and x is always incremented.
5746 DestRect.right = lprc->right + dc->ptlDCOrig.x;
5747 DoBreak = TRUE;
5748 }
5749 if (lprc && (fuOptions & ETO_CLIPPED) &&
5750 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
5751 {
5752 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
5753 }
5754 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5755 if (!IntEngMaskBlt(
5756 SurfObj,
5757 SourceGlyphSurf,
5758 &dc->co.ClipObj,
5759 &exloRGB2Dst.xlo,
5760 &exloDst2RGB.xlo,
5761 &DestRect,
5762 (PPOINTL)&MaskRect,
5763 &dc->eboText.BrushObject,
5764 &BrushOrigin))
5765 {
5766 DPRINT1("Failed to MaskBlt a glyph!\n");
5767 }
5768
5769 MouseSafetyOnDrawEnd(dc->ppdev) ;
5770
5771 EngUnlockSurface(SourceGlyphSurf);
5772 EngDeleteSurface((HSURF)HSourceGlyph);
5773 }
5774
5775 if (DoBreak)
5776 {
5777 break;
5778 }
5779
5780 if (plf->lfUnderline)
5781 {
5782 int i, position;
5783 if (!face->units_per_EM)
5784 {
5785 position = 0;
5786 }
5787 else
5788 {
5789 position = face->underline_position *
5790 face->size->metrics.y_ppem / face->units_per_EM;
5791 }
5792 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5793 {
5794 EngLineTo(SurfObj,
5795 &dc->co.ClipObj,
5796 &dc->eboText.BrushObject,
5797 (TextLeft >> 6),
5798 TextTop + yoff - position + i,
5799 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5800 TextTop + yoff - position + i,
5801 NULL,
5802 ROP2_TO_MIX(R2_COPYPEN));
5803 }
5804 }
5805 if (plf->lfStrikeOut)
5806 {
5807 int i;
5808 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5809 {
5810 EngLineTo(SurfObj,
5811 &dc->co.ClipObj,
5812 &dc->eboText.BrushObject,
5813 (TextLeft >> 6),
5814 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5815 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5816 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5817 NULL,
5818 ROP2_TO_MIX(R2_COPYPEN));
5819 }
5820 }
5821
5822 if (NULL == Dx)
5823 {
5824 TextLeft += realglyph->root.advance.x >> 10;
5825 DPRINT("New TextLeft: %I64d\n", TextLeft);
5826 }
5827 else
5828 {
5829 // FIXME this should probably be a matrix transform with TextTop as well.
5830 Scale = pdcattr->mxWorldToDevice.efM11;
5831 if (FLOATOBJ_Equal0(&Scale))
5832 FLOATOBJ_Set1(&Scale);
5833
5834 /* do the shift before multiplying to preserve precision */
5835 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5836 TextLeft += FLOATOBJ_GetLong(&Scale);
5837 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5838 }
5839
5840 if (DxShift)
5841 {
5842 TextTop -= Dx[2 * i + 1] << 6;
5843 }
5844
5845 previous = glyph_index;
5846
5847 if (EmuBold || EmuItalic)
5848 {
5849 FT_Done_Glyph((FT_Glyph)realglyph);
5850 realglyph = NULL;
5851 }
5852 }
5853
5854 if (pdcattr->lTextAlign & TA_UPDATECP) {
5855 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
5856 }
5857
5858 IntUnLockFreeType;
5859
5860 DC_vFinishBlit(dc, NULL) ;
5861
5862 EXLATEOBJ_vCleanup(&exloRGB2Dst);
5863 EXLATEOBJ_vCleanup(&exloDst2RGB);
5864 if (TextObj != NULL)
5865 TEXTOBJ_UnlockText(TextObj);
5866 good:
5867 DC_UnlockDc( dc );
5868
5869 return TRUE;
5870
5871 fail2:
5872 EXLATEOBJ_vCleanup(&exloRGB2Dst);
5873 EXLATEOBJ_vCleanup(&exloDst2RGB);
5874 fail:
5875 if (TextObj != NULL)
5876 TEXTOBJ_UnlockText(TextObj);
5877
5878 DC_UnlockDc(dc);
5879
5880 return FALSE;
5881 }
5882
5883 #define STACK_TEXT_BUFFER_SIZE 100
5884 BOOL
5885 APIENTRY
5886 NtGdiExtTextOutW(
5887 IN HDC hDC,
5888 IN INT XStart,
5889 IN INT YStart,
5890 IN UINT fuOptions,
5891 IN OPTIONAL LPRECT UnsafeRect,
5892 IN LPWSTR UnsafeString,
5893 IN INT Count,
5894 IN OPTIONAL LPINT UnsafeDx,
5895 IN DWORD dwCodePage)
5896 {
5897 BOOL Result = FALSE;
5898 NTSTATUS Status = STATUS_SUCCESS;
5899 RECTL SafeRect;
5900 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
5901 PVOID Buffer = LocalBuffer;
5902 LPCWSTR SafeString = NULL;
5903 LPINT SafeDx = NULL;
5904 ULONG BufSize, StringSize, DxSize = 0;
5905
5906 /* Check if String is valid */
5907 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
5908 {
5909 EngSetLastError(ERROR_INVALID_PARAMETER);
5910 return FALSE;
5911 }
5912
5913 if (Count > 0)
5914 {
5915 /* Calculate buffer size for string and Dx values */
5916 BufSize = StringSize = Count * sizeof(WCHAR);
5917 if (UnsafeDx)
5918 {
5919 /* If ETO_PDY is specified, we have pairs of INTs */
5920 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
5921 BufSize += DxSize;
5922 }
5923
5924 /* Check if our local buffer is large enough */
5925 if (BufSize > STACK_TEXT_BUFFER_SIZE)
5926 {
5927 /* It's not, allocate a temp buffer */
5928 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
5929 if (!Buffer)
5930 {
5931 return FALSE;
5932 }
5933 }
5934
5935 /* Probe and copy user mode data to the buffer */
5936 _SEH2_TRY
5937 {
5938 /* Put the Dx before the String to assure alignment of 4 */
5939 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
5940
5941 /* Probe and copy the string */
5942 ProbeForRead(UnsafeString, StringSize, 1);
5943 memcpy((PVOID)SafeString, UnsafeString, StringSize);
5944
5945 /* If we have Dx values... */
5946 if (UnsafeDx)
5947 {
5948 /* ... probe and copy them */
5949 SafeDx = Buffer;
5950 ProbeForRead(UnsafeDx, DxSize, 1);
5951 memcpy(SafeDx, UnsafeDx, DxSize);
5952 }
5953 }
5954 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5955 {
5956 Status = _SEH2_GetExceptionCode();
5957 }
5958 _SEH2_END
5959 if (!NT_SUCCESS(Status))
5960 {
5961 goto cleanup;
5962 }
5963 }
5964
5965 /* If we have a rect, copy it */
5966 if (UnsafeRect)
5967 {
5968 _SEH2_TRY
5969 {
5970 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
5971 SafeRect = *UnsafeRect;
5972 }
5973 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5974 {
5975 Status = _SEH2_GetExceptionCode();
5976 }
5977 _SEH2_END
5978 if (!NT_SUCCESS(Status))
5979 {
5980 goto cleanup;
5981 }
5982 }
5983
5984 /* Finally call the internal routine */
5985 Result = GreExtTextOutW(hDC,
5986 XStart,
5987 YStart,
5988 fuOptions,
5989 &SafeRect,
5990 SafeString,
5991 Count,
5992 SafeDx,
5993 dwCodePage);
5994
5995 cleanup:
5996 /* If we allocated a buffer, free it */
5997 if (Buffer != LocalBuffer)
5998 {
5999 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6000 }
6001
6002 return Result;
6003 }
6004
6005
6006 /*
6007 * @implemented
6008 */
6009 BOOL
6010 APIENTRY
6011 NtGdiGetCharABCWidthsW(
6012 IN HDC hDC,
6013 IN UINT FirstChar,
6014 IN ULONG Count,
6015 IN OPTIONAL PWCHAR UnSafepwch,
6016 IN FLONG fl,
6017 OUT PVOID Buffer)
6018 {
6019 LPABC SafeBuff;
6020 LPABCFLOAT SafeBuffF = NULL;
6021 PDC dc;
6022 PDC_ATTR pdcattr;
6023 PTEXTOBJ TextObj;
6024 PFONTGDI FontGDI;
6025 FT_Face face;
6026 FT_CharMap charmap, found = NULL;
6027 UINT i, glyph_index, BufferSize;
6028 HFONT hFont = 0;
6029 NTSTATUS Status = STATUS_SUCCESS;
6030 PMATRIX pmxWorldToDevice;
6031 PWCHAR Safepwch = NULL;
6032 LOGFONTW *plf;
6033
6034 if (!Buffer)
6035 {
6036 EngSetLastError(ERROR_INVALID_PARAMETER);
6037 return FALSE;
6038 }
6039
6040 if (UnSafepwch)
6041 {
6042 UINT pwchSize = Count * sizeof(WCHAR);
6043 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
6044
6045 if(!Safepwch)
6046 {
6047 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6048 return FALSE;
6049 }
6050
6051 _SEH2_TRY
6052 {
6053 ProbeForRead(UnSafepwch, pwchSize, 1);
6054 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
6055 }
6056 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6057 {
6058 Status = _SEH2_GetExceptionCode();
6059 }
6060 _SEH2_END;
6061 }
6062
6063 if (!NT_SUCCESS(Status))
6064 {
6065 if(Safepwch)
6066 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6067
6068 EngSetLastError(Status);
6069 return FALSE;
6070 }
6071
6072 BufferSize = Count * sizeof(ABC); // Same size!
6073 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6074 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
6075 if (SafeBuff == NULL)
6076 {
6077
6078 if(Safepwch)
6079 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6080
6081 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6082 return FALSE;
6083 }
6084
6085 dc = DC_LockDc(hDC);
6086 if (dc == NULL)
6087 {
6088 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6089
6090 if(Safepwch)
6091 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6092
6093 EngSetLastError(ERROR_INVALID_HANDLE);
6094 return FALSE;
6095 }
6096 pdcattr = dc->pdcattr;
6097 hFont = pdcattr->hlfntNew;
6098 TextObj = RealizeFontInit(hFont);
6099
6100 /* Get the DC's world-to-device transformation matrix */
6101 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6102 DC_UnlockDc(dc);
6103
6104 if (TextObj == NULL)
6105 {
6106 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6107
6108 if(Safepwch)
6109 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6110
6111 EngSetLastError(ERROR_INVALID_HANDLE);
6112 return FALSE;
6113 }
6114
6115 FontGDI = ObjToGDI(TextObj->Font, FONT);
6116
6117 face = FontGDI->SharedFace->Face;
6118 if (face->charmap == NULL)
6119 {
6120 for (i = 0; i < (UINT)face->num_charmaps; i++)
6121 {
6122 charmap = face->charmaps[i];
6123 if (charmap->encoding != 0)
6124 {
6125 found = charmap;
6126 break;
6127 }
6128 }
6129
6130 if (!found)
6131 {
6132 DPRINT1("WARNING: Could not find desired charmap!\n");
6133 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6134
6135 if(Safepwch)
6136 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6137
6138 EngSetLastError(ERROR_INVALID_HANDLE);
6139 return FALSE;
6140 }
6141
6142 IntLockFreeType;
6143 FT_Set_Charmap(face, found);
6144 IntUnLockFreeType;
6145 }
6146
6147 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6148 IntLockFreeType;
6149 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
6150 FtSetCoordinateTransform(face, pmxWorldToDevice);
6151
6152 for (i = FirstChar; i < FirstChar+Count; i++)
6153 {
6154 int adv, lsb, bbx, left, right;
6155
6156 if (Safepwch)
6157 {
6158 if (fl & GCABCW_INDICES)
6159 glyph_index = Safepwch[i - FirstChar];
6160 else
6161 glyph_index = FT_Get_Char_Index(face, Safepwch[i - FirstChar]);
6162 }
6163 else
6164 {
6165 if (fl & GCABCW_INDICES)
6166 glyph_index = i;
6167 else
6168 glyph_index = FT_Get_Char_Index(face, i);
6169 }
6170 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6171
6172 left = (INT)face->glyph->metrics.horiBearingX & -64;
6173 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
6174 adv = (face->glyph->advance.x + 32) >> 6;
6175
6176 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
6177 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
6178
6179 lsb = left >> 6;
6180 bbx = (right - left) >> 6;
6181 /*
6182 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
6183 */
6184 if (!fl)
6185 {
6186 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
6187 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
6188 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
6189 }
6190 else
6191 {
6192 SafeBuff[i - FirstChar].abcA = lsb;
6193 SafeBuff[i - FirstChar].abcB = bbx;
6194 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
6195 }
6196 }
6197 IntUnLockFreeType;
6198 TEXTOBJ_UnlockText(TextObj);
6199 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6200
6201 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6202
6203 if(Safepwch)
6204 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
6205
6206 if (! NT_SUCCESS(Status))
6207 {
6208 SetLastNtError(Status);
6209 return FALSE;
6210 }
6211
6212 DPRINT("NtGdiGetCharABCWidths Worked!\n");
6213 return TRUE;
6214 }
6215
6216 /*
6217 * @implemented
6218 */
6219 BOOL
6220 APIENTRY
6221 NtGdiGetCharWidthW(
6222 IN HDC hDC,
6223 IN UINT FirstChar,
6224 IN UINT Count,
6225 IN OPTIONAL PWCHAR UnSafepwc,
6226 IN FLONG fl,
6227 OUT PVOID Buffer)
6228 {
6229 NTSTATUS Status = STATUS_SUCCESS;
6230 LPINT SafeBuff;
6231 PFLOAT SafeBuffF = NULL;
6232 PDC dc;
6233 PDC_ATTR pdcattr;
6234 PTEXTOBJ TextObj;
6235 PFONTGDI FontGDI;
6236 FT_Face face;
6237 FT_CharMap charmap, found = NULL;
6238 UINT i, glyph_index, BufferSize;
6239 HFONT hFont = 0;
6240 PMATRIX pmxWorldToDevice;
6241 PWCHAR Safepwc = NULL;
6242 LOGFONTW *plf;
6243
6244 if (UnSafepwc)
6245 {
6246 UINT pwcSize = Count * sizeof(WCHAR);
6247 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6248
6249 if(!Safepwc)
6250 {
6251 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6252 return FALSE;
6253 }
6254 _SEH2_TRY
6255 {
6256 ProbeForRead(UnSafepwc, pwcSize, 1);
6257 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6258 }
6259 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6260 {
6261 Status = _SEH2_GetExceptionCode();
6262 }
6263 _SEH2_END;
6264 }
6265
6266 if (!NT_SUCCESS(Status))
6267 {
6268 EngSetLastError(Status);
6269 return FALSE;
6270 }
6271
6272 BufferSize = Count * sizeof(INT); // Same size!
6273 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
6274 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
6275 if (SafeBuff == NULL)
6276 {
6277 if(Safepwc)
6278 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6279
6280 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6281 return FALSE;
6282 }
6283
6284 dc = DC_LockDc(hDC);
6285 if (dc == NULL)
6286 {
6287 if(Safepwc)
6288 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6289
6290 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6291 EngSetLastError(ERROR_INVALID_HANDLE);
6292 return FALSE;
6293 }
6294 pdcattr = dc->pdcattr;
6295 hFont = pdcattr->hlfntNew;
6296 TextObj = RealizeFontInit(hFont);
6297 /* Get the DC's world-to-device transformation matrix */
6298 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6299 DC_UnlockDc(dc);
6300
6301 if (TextObj == NULL)
6302 {
6303 if(Safepwc)
6304 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6305
6306 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6307 EngSetLastError(ERROR_INVALID_HANDLE);
6308 return FALSE;
6309 }
6310
6311 FontGDI = ObjToGDI(TextObj->Font, FONT);
6312
6313 face = FontGDI->SharedFace->Face;
6314 if (face->charmap == NULL)
6315 {
6316 for (i = 0; i < (UINT)face->num_charmaps; i++)
6317 {
6318 charmap = face->charmaps[i];
6319 if (charmap->encoding != 0)
6320 {
6321 found = charmap;
6322 break;
6323 }
6324 }
6325
6326 if (!found)
6327 {
6328 DPRINT1("WARNING: Could not find desired charmap!\n");
6329
6330 if(Safepwc)
6331 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6332
6333 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6334 EngSetLastError(ERROR_INVALID_HANDLE);
6335 return FALSE;
6336 }
6337
6338 IntLockFreeType;
6339 FT_Set_Charmap(face, found);
6340 IntUnLockFreeType;
6341 }
6342
6343 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6344 IntLockFreeType;
6345 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
6346 FtSetCoordinateTransform(face, pmxWorldToDevice);
6347
6348 for (i = FirstChar; i < FirstChar+Count; i++)
6349 {
6350 if (Safepwc)
6351 {
6352 if (fl & GCW_INDICES)
6353 glyph_index = Safepwc[i - FirstChar];
6354 else
6355 glyph_index = FT_Get_Char_Index(face, Safepwc[i - FirstChar]);
6356 }
6357 else
6358 {
6359 if (fl & GCW_INDICES)
6360 glyph_index = i;
6361 else
6362 glyph_index = FT_Get_Char_Index(face, i);
6363 }
6364 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
6365 if (!fl)
6366 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
6367 else
6368 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
6369 }
6370 IntUnLockFreeType;
6371 TEXTOBJ_UnlockText(TextObj);
6372 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
6373
6374 if(Safepwc)
6375 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6376
6377 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
6378 return TRUE;
6379 }
6380
6381
6382 /*
6383 * @implemented
6384 */
6385 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
6386 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
6387 // NOTE: See also GreGetGlyphIndicesW.
6388 __kernel_entry
6389 W32KAPI
6390 DWORD
6391 APIENTRY
6392 NtGdiGetGlyphIndicesW(
6393 _In_ HDC hdc,
6394 _In_reads_opt_(cwc) LPCWSTR pwc,
6395 _In_ INT cwc,
6396 _Out_writes_opt_(cwc) LPWORD pgi,
6397 _In_ DWORD iMode)
6398 {
6399 PDC dc;
6400 PDC_ATTR pdcattr;
6401 PTEXTOBJ TextObj;
6402 PFONTGDI FontGDI;
6403 HFONT hFont = NULL;
6404 NTSTATUS Status = STATUS_SUCCESS;
6405 OUTLINETEXTMETRICW *potm;
6406 INT i;
6407 WCHAR DefChar = 0xffff;
6408 PWSTR Buffer = NULL;
6409 ULONG Size, pwcSize;
6410 PWSTR Safepwc = NULL;
6411 LPCWSTR UnSafepwc = pwc;
6412 LPWORD UnSafepgi = pgi;
6413
6414 /* Check for integer overflow */
6415 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN
6416 return GDI_ERROR;
6417
6418 if (!UnSafepwc && !UnSafepgi)
6419 return cwc;
6420
6421 if (!UnSafepwc || !UnSafepgi)
6422 {
6423 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
6424 return GDI_ERROR;
6425 }
6426
6427 // TODO: Special undocumented case!
6428 if (!pwc && !pgi && (cwc == 0))
6429 {
6430 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n");
6431 return 0;
6432 }
6433
6434 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825
6435 if (cwc == 0)
6436 {
6437 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n");
6438 return GDI_ERROR;
6439 }
6440
6441 dc = DC_LockDc(hdc);
6442 if (!dc)
6443 {
6444 return GDI_ERROR;
6445 }
6446 pdcattr = dc->pdcattr;
6447 hFont = pdcattr->hlfntNew;
6448 TextObj = RealizeFontInit(hFont);
6449 DC_UnlockDc(dc);
6450 if (!TextObj)
6451 {
6452 return GDI_ERROR;
6453 }
6454
6455 FontGDI = ObjToGDI(TextObj->Font, FONT);
6456 TEXTOBJ_UnlockText(TextObj);
6457
6458 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
6459 if (!Buffer)
6460 {
6461 return GDI_ERROR;
6462 }
6463
6464 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
6465 {
6466 DefChar = 0xffff;
6467 }
6468 else
6469 {
6470 FT_Face Face = FontGDI->SharedFace->Face;
6471 if (FT_IS_SFNT(Face))
6472 {
6473 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
6474 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(Face, pOS2->usDefaultChar) : 0);
6475 }
6476 else
6477 {
6478 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
6479 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
6480 if (!potm)
6481 {
6482 cwc = GDI_ERROR;
6483 goto ErrorRet;
6484 }
6485 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
6486 if (Size)
6487 DefChar = potm->otmTextMetrics.tmDefaultChar;
6488 ExFreePoolWithTag(potm, GDITAG_TEXT);
6489 }
6490 }
6491
6492 pwcSize = cwc * sizeof(WCHAR);
6493 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
6494
6495 if (!Safepwc)
6496 {
6497 Status = STATUS_NO_MEMORY;
6498 goto ErrorRet;
6499 }
6500
6501 _SEH2_TRY
6502 {
6503 ProbeForRead(UnSafepwc, pwcSize, 1);
6504 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
6505 }
6506 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6507 {
6508 Status = _SEH2_GetExceptionCode();
6509 }
6510 _SEH2_END;
6511
6512 if (!NT_SUCCESS(Status)) goto ErrorRet;
6513
6514 IntLockFreeType;
6515
6516 for (i = 0; i < cwc; i++)
6517 {
6518 Buffer[i] = FT_Get_Char_Index(FontGDI->SharedFace->Face, Safepwc[i]);
6519 if (Buffer[i] == 0)
6520 {
6521 Buffer[i] = DefChar;
6522 }
6523 }
6524
6525 IntUnLockFreeType;
6526
6527 _SEH2_TRY
6528 {
6529 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
6530 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
6531 }
6532 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6533 {
6534 Status = _SEH2_GetExceptionCode();
6535 }
6536 _SEH2_END;
6537
6538 ErrorRet:
6539 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
6540 if (Safepwc != NULL)
6541 {
6542 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
6543 }
6544 if (NT_SUCCESS(Status)) return cwc;
6545 return GDI_ERROR;
6546 }
6547
6548 /* EOF */