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