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