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