1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PURPOSE: FreeType font engine interface
5 * PROGRAMMERS: Copyright 2001 Huw D M Davies for CodeWeavers.
6 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7 * Copyright 2016-2024 Katayama Hirofumi MZ.
8 */
9
10 /** Includes ******************************************************************/
11
12 #include <win32k.h>
13
14 #include FT_GLYPH_H
15 #include FT_TYPE1_TABLES_H
16 #include FT_TRUETYPE_TABLES_H
17 #include FT_TRUETYPE_TAGS_H
18 #include FT_TRIGONOMETRY_H
19 #include FT_BITMAP_H
20 #include FT_OUTLINE_H
21 #include FT_WINFONTS_H
22 #include FT_SFNT_NAMES_H
23 #include FT_SYNTHESIS_H
24 #include FT_TRUETYPE_IDS_H
25
26 #ifndef FT_INTERNAL_INTERNAL_H
27 #define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h>
28 #include FT_INTERNAL_INTERNAL_H
29 #endif
30 #include FT_INTERNAL_TRUETYPE_TYPES_H
31
32 #include <gdi/eng/floatobj.h>
33 #include "font.h"
34
35 #define NDEBUG
36 #include <debug.h>
37
38 typedef struct _FONTLINK
39 {
40 LIST_ENTRY ListEntry; //< Entry in the FONTLINK_CHAIN::FontLinkList
41 BOOL bIgnore;
42 LOGFONTW LogFont;
43 PSHARED_FACE SharedFace;
44 } FONTLINK, *PFONTLINK;
45
46 typedef struct _FONTLINK_CHAIN
47 {
48 LIST_ENTRY FontLinkList; //< List of FONTLINK's
49 LOGFONTW LogFont;
50 PZZWSTR pszzFontLink;
51 PTEXTOBJ pBaseTextObj;
52 FT_Face pDefFace;
53 } FONTLINK_CHAIN, *PFONTLINK_CHAIN;
54
55 typedef struct _FONTLINK_CACHE
56 {
57 LIST_ENTRY ListEntry;
58 LOGFONTW LogFont;
59 FONTLINK_CHAIN Chain;
60 } FONTLINK_CACHE, *PFONTLINK_CACHE;
61
62 #define FONTLINK_DEFAULT_CHAR 0x30FB // U+30FB (KATAKANA MIDDLE DOT)
63
64 static DWORD s_chFontLinkDefaultChar = FONTLINK_DEFAULT_CHAR;
65 static WCHAR s_szDefFontLinkFileName[MAX_PATH] = L"";
66 static WCHAR s_szDefFontLinkFontName[MAX_PATH] = L"";
67 static BOOL s_fFontLinkUseAnsi = FALSE;
68 static BOOL s_fFontLinkUseOem = FALSE;
69 static BOOL s_fFontLinkUseSymbol = FALSE;
70
71 #define MAX_FONTLINK_CACHE 128
72 static RTL_STATIC_LIST_HEAD(g_FontLinkCache); // The list of FONTLINK_CACHE
73 static LONG g_nFontLinkCacheCount = 0;
74
75 static SIZE_T
SZZ_GetSize(_In_ PCZZWSTR pszz)76 SZZ_GetSize(_In_ PCZZWSTR pszz)
77 {
78 SIZE_T ret = 0, cch;
79 const WCHAR *pch = pszz;
80 while (*pch)
81 {
82 cch = wcslen(pch) + 1;
83 ret += cch;
84 pch += cch;
85 }
86 ++ret;
87 return ret * sizeof(WCHAR);
88 }
89
90 static inline NTSTATUS
FontLink_LoadSettings(VOID)91 FontLink_LoadSettings(VOID)
92 {
93 NTSTATUS Status;
94 HKEY hKey;
95 DWORD cbData, dwValue;
96
97 // Set the default values
98 s_chFontLinkDefaultChar = FONTLINK_DEFAULT_CHAR;
99
100 // Open the registry key
101 Status = RegOpenKey(
102 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink",
103 &hKey);
104 if (!NT_SUCCESS(Status))
105 return Status;
106
107 cbData = sizeof(dwValue);
108 Status = RegQueryValue(hKey, L"FontLinkDefaultChar", REG_DWORD, &dwValue, &cbData);
109 if (NT_SUCCESS(Status) && cbData == sizeof(dwValue))
110 s_chFontLinkDefaultChar = dwValue;
111
112 ZwClose(hKey); // Close the registry key
113 return STATUS_SUCCESS;
114 }
115
116 static inline NTSTATUS
FontLink_LoadDefaultFonts(VOID)117 FontLink_LoadDefaultFonts(VOID)
118 {
119 NTSTATUS Status;
120 HKEY hKey;
121 DWORD cbData;
122 WCHAR szValue[MAX_PATH];
123
124 // Set the default values
125 s_szDefFontLinkFileName[0] = s_szDefFontLinkFontName[0] = UNICODE_NULL;
126
127 // Open the registry key
128 Status = RegOpenKey(
129 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\FontAssoc\\Associated DefaultFonts",
130 &hKey);
131 if (!NT_SUCCESS(Status))
132 return Status;
133
134 cbData = sizeof(szValue);
135 Status = RegQueryValue(hKey, L"AssocSystemFont", REG_SZ, szValue, &cbData);
136 if (NT_SUCCESS(Status))
137 {
138 szValue[_countof(szValue) - 1] = UNICODE_NULL; // Avoid buffer overrun
139 RtlStringCchCopyW(s_szDefFontLinkFileName, _countof(s_szDefFontLinkFileName), szValue);
140 }
141
142 cbData = sizeof(szValue);
143 Status = RegQueryValue(hKey, L"FontPackage", REG_SZ, szValue, &cbData);
144 if (NT_SUCCESS(Status))
145 {
146 szValue[_countof(szValue) - 1] = UNICODE_NULL; // Avoid buffer overrun
147 RtlStringCchCopyW(s_szDefFontLinkFontName, _countof(s_szDefFontLinkFontName), szValue);
148 }
149
150 ZwClose(hKey); // Close the registry key
151 return STATUS_SUCCESS;
152 }
153
154 static inline NTSTATUS
FontLink_LoadDefaultCharset(VOID)155 FontLink_LoadDefaultCharset(VOID)
156 {
157 NTSTATUS Status;
158 HKEY hKey;
159 DWORD cbData;
160 WCHAR szValue[8];
161
162 // Set the default values
163 s_fFontLinkUseAnsi = s_fFontLinkUseOem = s_fFontLinkUseSymbol = FALSE;
164
165 // Open the registry key
166 Status = RegOpenKey(
167 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\FontAssoc\\Associated Charset",
168 &hKey);
169 if (!NT_SUCCESS(Status))
170 return Status;
171
172 cbData = sizeof(szValue);
173 Status = RegQueryValue(hKey, L"ANSI(00)", REG_SZ, szValue, &cbData);
174 if (NT_SUCCESS(Status))
175 {
176 szValue[_countof(szValue) - 1] = UNICODE_NULL; // Avoid buffer overrun
177 s_fFontLinkUseAnsi = !_wcsicmp(szValue, L"YES");
178 }
179
180 cbData = sizeof(szValue);
181 Status = RegQueryValue(hKey, L"OEM(FF)", REG_SZ, szValue, &cbData);
182 if (NT_SUCCESS(Status))
183 {
184 szValue[_countof(szValue) - 1] = UNICODE_NULL; // Avoid buffer overrun
185 s_fFontLinkUseOem = !_wcsicmp(szValue, L"YES");
186 }
187
188 cbData = sizeof(szValue);
189 Status = RegQueryValue(hKey, L"SYMBOL(02)", REG_SZ, szValue, &cbData);
190 if (NT_SUCCESS(Status))
191 {
192 szValue[_countof(szValue) - 1] = UNICODE_NULL; // Avoid buffer overrun
193 s_fFontLinkUseSymbol = !_wcsicmp(szValue, L"YES");
194 }
195
196 ZwClose(hKey); // Close the registry key
197 return STATUS_SUCCESS;
198 }
199
200 static inline VOID
FontLink_Destroy(_Inout_ PFONTLINK pLink)201 FontLink_Destroy(_Inout_ PFONTLINK pLink)
202 {
203 ASSERT(pLink);
204 ExFreePoolWithTag(pLink, TAG_FONT);
205 }
206
207 static inline BOOL
FontLink_Chain_IsPopulated(const FONTLINK_CHAIN * pChain)208 FontLink_Chain_IsPopulated(const FONTLINK_CHAIN *pChain)
209 {
210 return pChain->LogFont.lfFaceName[0];
211 }
212
213 static VOID
FontLink_Chain_Free(_Inout_ PFONTLINK_CHAIN pChain)214 FontLink_Chain_Free(
215 _Inout_ PFONTLINK_CHAIN pChain)
216 {
217 PLIST_ENTRY Entry;
218 PFONTLINK pLink;
219
220 if (!FontLink_Chain_IsPopulated(pChain)) // The chain is not populated yet
221 return;
222
223 if (pChain->pszzFontLink)
224 ExFreePoolWithTag(pChain->pszzFontLink, TAG_FONT);
225
226 while (!IsListEmpty(&pChain->FontLinkList))
227 {
228 Entry = RemoveHeadList(&pChain->FontLinkList);
229 pLink = CONTAINING_RECORD(Entry, FONTLINK, ListEntry);
230 FontLink_Destroy(pLink);
231 }
232 }
233
234 static inline VOID
FontLink_AddCache(_In_ PFONTLINK_CACHE pCache)235 FontLink_AddCache(
236 _In_ PFONTLINK_CACHE pCache)
237 {
238 PLIST_ENTRY Entry;
239
240 /* Add the new cache entry to the top of the cache list */
241 ++g_nFontLinkCacheCount;
242 InsertHeadList(&g_FontLinkCache, &pCache->ListEntry);
243
244 /* If there are too many cache entries in the list, remove the oldest one at the bottom */
245 if (g_nFontLinkCacheCount > MAX_FONTLINK_CACHE)
246 {
247 ASSERT(!IsListEmpty(&g_FontLinkCache));
248 Entry = RemoveTailList(&g_FontLinkCache);
249 --g_nFontLinkCacheCount;
250 pCache = CONTAINING_RECORD(Entry, FONTLINK_CACHE, ListEntry);
251 FontLink_Chain_Free(&pCache->Chain);
252 ExFreePoolWithTag(pCache, TAG_FONT);
253 }
254 }
255
256 static inline VOID
IntRebaseList(_Inout_ PLIST_ENTRY pNewHead,_Inout_ PLIST_ENTRY pOldHead)257 IntRebaseList(
258 _Inout_ PLIST_ENTRY pNewHead,
259 _Inout_ PLIST_ENTRY pOldHead)
260 {
261 PLIST_ENTRY Entry;
262
263 ASSERT(pNewHead != pOldHead);
264
265 InitializeListHead(pNewHead);
266 while (!IsListEmpty(pOldHead))
267 {
268 Entry = RemoveTailList(pOldHead);
269 InsertHeadList(pNewHead, Entry);
270 }
271 }
272
273 /// Add the chain to the cache (g_FontLinkCache) if the chain had been populated.
274 /// @param pChain The chain.
275 static inline VOID
FontLink_Chain_Finish(_Inout_ PFONTLINK_CHAIN pChain)276 FontLink_Chain_Finish(
277 _Inout_ PFONTLINK_CHAIN pChain)
278 {
279 PFONTLINK_CACHE pCache;
280
281 if (!FontLink_Chain_IsPopulated(pChain))
282 return; // The chain is not populated yet
283
284 pCache = ExAllocatePoolWithTag(PagedPool, sizeof(FONTLINK_CACHE), TAG_FONT);
285 if (!pCache)
286 return; // Out of memory
287
288 pCache->LogFont = pChain->LogFont;
289 pCache->Chain = *pChain;
290 IntRebaseList(&pCache->Chain.FontLinkList, &pChain->FontLinkList);
291
292 FontLink_AddCache(pCache);
293 }
294
295 static inline PFONTLINK_CACHE
FontLink_FindCache(_In_ const LOGFONTW * pLogFont)296 FontLink_FindCache(
297 _In_ const LOGFONTW* pLogFont)
298 {
299 PLIST_ENTRY Entry;
300 PFONTLINK_CACHE pLinkCache;
301 for (Entry = g_FontLinkCache.Flink; Entry != &g_FontLinkCache; Entry = Entry->Flink)
302 {
303 pLinkCache = CONTAINING_RECORD(Entry, FONTLINK_CACHE, ListEntry);
304 if (RtlEqualMemory(&pLinkCache->LogFont, pLogFont, sizeof(LOGFONTW)))
305 return pLinkCache;
306 }
307 return NULL;
308 }
309
310 static inline VOID
FontLink_CleanupCache(VOID)311 FontLink_CleanupCache(VOID)
312 {
313 PLIST_ENTRY Entry;
314 PFONTLINK_CACHE pLinkCache;
315
316 while (!IsListEmpty(&g_FontLinkCache))
317 {
318 Entry = RemoveHeadList(&g_FontLinkCache);
319 pLinkCache = CONTAINING_RECORD(Entry, FONTLINK_CACHE, ListEntry);
320 FontLink_Chain_Free(&pLinkCache->Chain);
321 ExFreePoolWithTag(pLinkCache, TAG_FONT);
322 }
323
324 g_nFontLinkCacheCount = 0;
325 }
326
327 /* The ranges of the surrogate pairs */
328 #define HIGH_SURROGATE_MIN 0xD800U
329 #define HIGH_SURROGATE_MAX 0xDBFFU
330 #define LOW_SURROGATE_MIN 0xDC00U
331 #define LOW_SURROGATE_MAX 0xDFFFU
332
333 #define IS_HIGH_SURROGATE(ch0) (HIGH_SURROGATE_MIN <= (ch0) && (ch0) <= HIGH_SURROGATE_MAX)
334 #define IS_LOW_SURROGATE(ch1) (LOW_SURROGATE_MIN <= (ch1) && (ch1) <= LOW_SURROGATE_MAX)
335
336 static inline DWORD
Utf32FromSurrogatePair(DWORD ch0,DWORD ch1)337 Utf32FromSurrogatePair(DWORD ch0, DWORD ch1)
338 {
339 return ((ch0 - HIGH_SURROGATE_MIN) << 10) + (ch1 - LOW_SURROGATE_MIN) + 0x10000;
340 }
341
342 /* TPMF_FIXED_PITCH is confusing; brain-dead api */
343 #ifndef _TMPF_VARIABLE_PITCH
344 #define _TMPF_VARIABLE_PITCH TMPF_FIXED_PITCH
345 #endif
346
347 /* Is bold emulation necessary? */
348 #define EMUBOLD_NEEDED(original, request) \
349 (((request) != FW_DONTCARE) && ((request) - (original) >= FW_BOLD - FW_MEDIUM))
350
351 extern const MATRIX gmxWorldToDeviceDefault;
352 extern const MATRIX gmxWorldToPageDefault;
353 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
354 static POINTL PointZero = { 0, 0 };
355
356 /* HACK!! Fix XFORMOBJ then use 1:16 / 16:1 */
357 #define gmxWorldToDeviceDefault gmxWorldToPageDefault
358
359 FT_Library g_FreeTypeLibrary;
360
361 /* registry */
362 static UNICODE_STRING g_FontRegPath =
363 RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
364
365
366 /* The FreeType library is not thread safe, so we have
367 to serialize access to it */
368 static PFAST_MUTEX g_FreeTypeLock;
369
370 static RTL_STATIC_LIST_HEAD(g_FontListHead);
371 static BOOL g_RenderingEnabled = TRUE;
372
373 #define ASSERT_FREETYPE_LOCK_HELD() \
374 ASSERT(g_FreeTypeLock->Owner == KeGetCurrentThread())
375
376 #define ASSERT_FREETYPE_LOCK_NOT_HELD() \
377 ASSERT(g_FreeTypeLock->Owner != KeGetCurrentThread())
378
379 #define IntLockFreeType() \
380 do { \
381 ASSERT_FREETYPE_LOCK_NOT_HELD(); \
382 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FreeTypeLock); \
383 } while (0)
384
385 #define IntUnLockFreeType() \
386 do { \
387 ASSERT_FREETYPE_LOCK_HELD(); \
388 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FreeTypeLock); \
389 } while(0)
390
391 #define MAX_FONT_CACHE 256
392
393 static RTL_STATIC_LIST_HEAD(g_FontCacheListHead);
394 static UINT g_FontCacheNumEntries;
395
396 static PWCHAR g_ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */
397 {
398 L"Western", /* 00 */
399 L"Central_European",
400 L"Cyrillic",
401 L"Greek",
402 L"Turkish",
403 L"Hebrew",
404 L"Arabic",
405 L"Baltic",
406 L"Vietnamese", /* 08 */
407 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */
408 L"Thai",
409 L"Japanese",
410 L"CHINESE_GB2312",
411 L"Hangul",
412 L"CHINESE_BIG5",
413 L"Hangul(Johab)",
414 NULL, NULL, /* 23 */
415 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
416 L"Symbol" /* 31 */
417 };
418
419 /*
420 * For TranslateCharsetInfo
421 */
422 #define CP_SYMBOL 42
423 #define MAXTCIINDEX 32
424 static const CHARSETINFO g_FontTci[MAXTCIINDEX] =
425 {
426 /* ANSI */
427 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
428 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
429 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
430 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
431 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
432 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
433 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
434 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
435 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
436 /* reserved by ANSI */
437 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
438 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
439 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
440 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
441 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
442 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
443 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
444 /* ANSI and OEM */
445 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
446 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
447 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
448 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
449 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
450 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
451 /* Reserved for alternate ANSI and OEM */
452 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
453 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
454 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
455 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
456 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
457 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
458 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
459 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
460 /* Reserved for system */
461 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
462 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
463 };
464
465 #ifndef CP_OEMCP
466 #define CP_OEMCP 1
467 #define CP_MACCP 2
468 #endif
469
470 /* Get charset from specified codepage.
471 g_FontTci is used also in TranslateCharsetInfo. */
IntCharSetFromCodePage(UINT uCodePage)472 BYTE FASTCALL IntCharSetFromCodePage(UINT uCodePage)
473 {
474 UINT i;
475
476 if (uCodePage == CP_OEMCP)
477 return OEM_CHARSET;
478
479 if (uCodePage == CP_MACCP)
480 return MAC_CHARSET;
481
482 for (i = 0; i < MAXTCIINDEX; ++i)
483 {
484 if (g_FontTci[i].ciACP == 0)
485 continue;
486
487 if (g_FontTci[i].ciACP == uCodePage)
488 return g_FontTci[i].ciCharset;
489 }
490
491 return DEFAULT_CHARSET;
492 }
493
494 static __inline VOID
495 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
496 const LOGFONTW *LogFont,
497 const PLIST_ENTRY Head);
498
499 static BOOL
500 MatchFontName(PSHARED_FACE SharedFace, PUNICODE_STRING Name1, FT_UShort NameID, FT_UShort LangID);
501
502 static BOOL
FontLink_PrepareFontInfo(_Inout_ PFONTLINK pFontLink)503 FontLink_PrepareFontInfo(
504 _Inout_ PFONTLINK pFontLink)
505 {
506 FONTOBJ *pFontObj;
507 ULONG MatchPenalty;
508 UNICODE_STRING FaceName;
509 PPROCESSINFO Win32Process;
510 PFONTGDI pFontGDI;
511
512 ASSERT_FREETYPE_LOCK_HELD();
513
514 if (pFontLink->bIgnore)
515 return FALSE;
516
517 if (pFontLink->SharedFace)
518 return TRUE;
519
520 MatchPenalty = MAXULONG;
521 pFontObj = NULL;
522
523 // Search private fonts
524 Win32Process = PsGetCurrentProcessWin32Process();
525 FindBestFontFromList(&pFontObj, &MatchPenalty, &pFontLink->LogFont,
526 &Win32Process->PrivateFontListHead);
527
528 // Search system fonts
529 FindBestFontFromList(&pFontObj, &MatchPenalty, &pFontLink->LogFont,
530 &g_FontListHead);
531
532 if (!pFontObj) // Not found?
533 {
534 pFontLink->bIgnore = TRUE;
535 return FALSE;
536 }
537
538 pFontGDI = ObjToGDI(pFontObj, FONT);
539 pFontLink->SharedFace = pFontGDI->SharedFace;
540
541 // FontLink uses family name
542 RtlInitUnicodeString(&FaceName, pFontLink->LogFont.lfFaceName);
543 if (!MatchFontName(pFontLink->SharedFace, &FaceName, TT_NAME_ID_FONT_FAMILY, LANG_ENGLISH) &&
544 !MatchFontName(pFontLink->SharedFace, &FaceName, TT_NAME_ID_FONT_FAMILY, gusLanguageID))
545 {
546 pFontLink->bIgnore = TRUE;
547 return FALSE;
548 }
549
550 return TRUE;
551 }
552
553 /* list head */
554 static RTL_STATIC_LIST_HEAD(g_FontSubstListHead);
555
556 static void
SharedMem_AddRef(PSHARED_MEM Ptr)557 SharedMem_AddRef(PSHARED_MEM Ptr)
558 {
559 ASSERT_FREETYPE_LOCK_HELD();
560
561 ++Ptr->RefCount;
562 }
563
564 static void
SharedFaceCache_Init(PSHARED_FACE_CACHE Cache)565 SharedFaceCache_Init(PSHARED_FACE_CACHE Cache)
566 {
567 Cache->OutlineRequiredSize = 0;
568 RtlInitUnicodeString(&Cache->FontFamily, NULL);
569 RtlInitUnicodeString(&Cache->FullName, NULL);
570 }
571
572 static PSHARED_FACE
SharedFace_Create(FT_Face Face,PSHARED_MEM Memory)573 SharedFace_Create(FT_Face Face, PSHARED_MEM Memory)
574 {
575 PSHARED_FACE Ptr;
576 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
577 if (Ptr)
578 {
579 Ptr->Face = Face;
580 Ptr->RefCount = 1;
581 Ptr->Memory = Memory;
582 SharedFaceCache_Init(&Ptr->EnglishUS);
583 SharedFaceCache_Init(&Ptr->UserLanguage);
584
585 SharedMem_AddRef(Memory);
586 DPRINT("Creating SharedFace for %s\n", Face->family_name ? Face->family_name : "<NULL>");
587 }
588 return Ptr;
589 }
590
591 static PSHARED_MEM
SharedMem_Create(PBYTE Buffer,ULONG BufferSize,BOOL IsMapping)592 SharedMem_Create(PBYTE Buffer, ULONG BufferSize, BOOL IsMapping)
593 {
594 PSHARED_MEM Ptr;
595 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_MEM), TAG_FONT);
596 if (Ptr)
597 {
598 Ptr->Buffer = Buffer;
599 Ptr->BufferSize = BufferSize;
600 Ptr->RefCount = 1;
601 Ptr->IsMapping = IsMapping;
602 DPRINT("Creating SharedMem for %p (%i, %p)\n", Buffer, IsMapping, Ptr);
603 }
604 return Ptr;
605 }
606
607 static void
SharedFace_AddRef(PSHARED_FACE Ptr)608 SharedFace_AddRef(PSHARED_FACE Ptr)
609 {
610 ASSERT_FREETYPE_LOCK_HELD();
611
612 ++Ptr->RefCount;
613 }
614
615 static void
RemoveCachedEntry(PFONT_CACHE_ENTRY Entry)616 RemoveCachedEntry(PFONT_CACHE_ENTRY Entry)
617 {
618 ASSERT_FREETYPE_LOCK_HELD();
619
620 FT_Done_Glyph((FT_Glyph)Entry->BitmapGlyph);
621 RemoveEntryList(&Entry->ListEntry);
622 ExFreePoolWithTag(Entry, TAG_FONT);
623 g_FontCacheNumEntries--;
624 ASSERT(g_FontCacheNumEntries <= MAX_FONT_CACHE);
625 }
626
627 static void
RemoveCacheEntries(FT_Face Face)628 RemoveCacheEntries(FT_Face Face)
629 {
630 PLIST_ENTRY CurrentEntry, NextEntry;
631 PFONT_CACHE_ENTRY FontEntry;
632
633 ASSERT_FREETYPE_LOCK_HELD();
634
635 for (CurrentEntry = g_FontCacheListHead.Flink;
636 CurrentEntry != &g_FontCacheListHead;
637 CurrentEntry = NextEntry)
638 {
639 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
640 NextEntry = CurrentEntry->Flink;
641
642 if (FontEntry->Hashed.Face == Face)
643 {
644 RemoveCachedEntry(FontEntry);
645 }
646 }
647 }
648
SharedMem_Release(PSHARED_MEM Ptr)649 static void SharedMem_Release(PSHARED_MEM Ptr)
650 {
651 ASSERT_FREETYPE_LOCK_HELD();
652 ASSERT(Ptr->RefCount > 0);
653
654 if (Ptr->RefCount <= 0)
655 return;
656
657 --Ptr->RefCount;
658 if (Ptr->RefCount == 0)
659 {
660 DPRINT("Releasing SharedMem for %p (%i, %p)\n", Ptr->Buffer, Ptr->IsMapping, Ptr);
661 if (Ptr->IsMapping)
662 MmUnmapViewInSystemSpace(Ptr->Buffer);
663 else
664 ExFreePoolWithTag(Ptr->Buffer, TAG_FONT);
665 ExFreePoolWithTag(Ptr, TAG_FONT);
666 }
667 }
668
669 static void
SharedFaceCache_Release(PSHARED_FACE_CACHE Cache)670 SharedFaceCache_Release(PSHARED_FACE_CACHE Cache)
671 {
672 RtlFreeUnicodeString(&Cache->FontFamily);
673 RtlFreeUnicodeString(&Cache->FullName);
674 }
675
676 static void
SharedFace_Release(PSHARED_FACE Ptr)677 SharedFace_Release(PSHARED_FACE Ptr)
678 {
679 IntLockFreeType();
680 ASSERT(Ptr->RefCount > 0);
681
682 if (Ptr->RefCount <= 0)
683 return;
684
685 --Ptr->RefCount;
686 if (Ptr->RefCount == 0)
687 {
688 DPRINT("Releasing SharedFace for %s\n", Ptr->Face->family_name ? Ptr->Face->family_name : "<NULL>");
689 RemoveCacheEntries(Ptr->Face);
690 FT_Done_Face(Ptr->Face);
691 SharedMem_Release(Ptr->Memory);
692 SharedFaceCache_Release(&Ptr->EnglishUS);
693 SharedFaceCache_Release(&Ptr->UserLanguage);
694 ExFreePoolWithTag(Ptr, TAG_FONT);
695 }
696 IntUnLockFreeType();
697 }
698
699
700 static VOID FASTCALL
CleanupFontEntryEx(PFONT_ENTRY FontEntry,PFONTGDI FontGDI)701 CleanupFontEntryEx(PFONT_ENTRY FontEntry, PFONTGDI FontGDI)
702 {
703 // PFONTGDI FontGDI = FontEntry->Font;
704 PSHARED_FACE SharedFace = FontGDI->SharedFace;
705
706 if (FontGDI->Filename)
707 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
708
709 if (FontEntry->StyleName.Buffer)
710 RtlFreeUnicodeString(&FontEntry->StyleName);
711
712 if (FontEntry->FaceName.Buffer)
713 RtlFreeUnicodeString(&FontEntry->FaceName);
714
715 EngFreeMem(FontGDI);
716 SharedFace_Release(SharedFace);
717 ExFreePoolWithTag(FontEntry, TAG_FONT);
718 }
719
720 static __inline VOID FASTCALL
CleanupFontEntry(PFONT_ENTRY FontEntry)721 CleanupFontEntry(PFONT_ENTRY FontEntry)
722 {
723 CleanupFontEntryEx(FontEntry, FontEntry->Font);
724 }
725
726
FTVectorToPOINTFX(FT_Vector * vec,POINTFX * pt)727 static __inline void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
728 {
729 pt->x.value = vec->x >> 6;
730 pt->x.fract = (vec->x & 0x3f) << 10;
731 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
732 pt->y.value = vec->y >> 6;
733 pt->y.fract = (vec->y & 0x3f) << 10;
734 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
735 }
736
737 /*
738 This function builds an FT_Fixed from a FIXED. It simply put f.value
739 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
740 */
FT_FixedFromFIXED(FIXED f)741 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
742 {
743 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
744 }
745
746
747 #if DBG
DumpFontEntry(PFONT_ENTRY FontEntry)748 VOID DumpFontEntry(PFONT_ENTRY FontEntry)
749 {
750 const char *family_name;
751 const char *style_name;
752 FT_Face Face;
753 PFONTGDI FontGDI = FontEntry->Font;
754
755 if (!FontGDI)
756 {
757 DPRINT("FontGDI NULL\n");
758 return;
759 }
760
761 Face = (FontGDI->SharedFace ? FontGDI->SharedFace->Face : NULL);
762 if (Face)
763 {
764 family_name = Face->family_name;
765 style_name = Face->style_name;
766 }
767 else
768 {
769 family_name = "<invalid>";
770 style_name = "<invalid>";
771 }
772
773 DPRINT("family_name '%s', style_name '%s', FaceName '%wZ', StyleName '%wZ', FontGDI %p, "
774 "FontObj %p, iUnique %lu, SharedFace %p, Face %p, CharSet %u, Filename '%S'\n",
775 family_name,
776 style_name,
777 &FontEntry->FaceName,
778 &FontEntry->StyleName,
779 FontGDI,
780 &FontGDI->FontObj,
781 FontGDI->iUnique,
782 FontGDI->SharedFace,
783 Face,
784 FontGDI->CharSet,
785 FontGDI->Filename);
786 }
787
DumpFontList(PLIST_ENTRY Head)788 VOID DumpFontList(PLIST_ENTRY Head)
789 {
790 PLIST_ENTRY Entry;
791 PFONT_ENTRY CurrentEntry;
792
793 DPRINT("## DumpFontList(%p)\n", Head);
794
795 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
796 {
797 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
798 DumpFontEntry(CurrentEntry);
799 }
800 }
801
DumpFontSubstEntry(PFONTSUBST_ENTRY pSubstEntry)802 VOID DumpFontSubstEntry(PFONTSUBST_ENTRY pSubstEntry)
803 {
804 DPRINT("%wZ,%u -> %wZ,%u\n",
805 &pSubstEntry->FontNames[FONTSUBST_FROM],
806 pSubstEntry->CharSets[FONTSUBST_FROM],
807 &pSubstEntry->FontNames[FONTSUBST_TO],
808 pSubstEntry->CharSets[FONTSUBST_TO]);
809 }
810
DumpFontSubstList(VOID)811 VOID DumpFontSubstList(VOID)
812 {
813 PLIST_ENTRY pHead = &g_FontSubstListHead;
814 PLIST_ENTRY pListEntry;
815 PFONTSUBST_ENTRY pSubstEntry;
816
817 DPRINT("## DumpFontSubstList\n");
818
819 for (pListEntry = pHead->Flink;
820 pListEntry != pHead;
821 pListEntry = pListEntry->Flink)
822 {
823 pSubstEntry = CONTAINING_RECORD(pListEntry, FONTSUBST_ENTRY, ListEntry);
824 DumpFontSubstEntry(pSubstEntry);
825 }
826 }
827
DumpPrivateFontList(BOOL bDoLock)828 VOID DumpPrivateFontList(BOOL bDoLock)
829 {
830 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
831
832 if (!Win32Process)
833 return;
834
835 if (bDoLock)
836 {
837 IntLockFreeType();
838 IntLockProcessPrivateFonts(Win32Process);
839 }
840
841 DumpFontList(&Win32Process->PrivateFontListHead);
842
843 if (bDoLock)
844 {
845 IntUnLockProcessPrivateFonts(Win32Process);
846 IntUnLockFreeType();
847 }
848 }
849
DumpGlobalFontList(BOOL bDoLock)850 VOID DumpGlobalFontList(BOOL bDoLock)
851 {
852 if (bDoLock)
853 IntLockFreeType();
854
855 DumpFontList(&g_FontListHead);
856
857 if (bDoLock)
858 IntUnLockFreeType();
859 }
860
DumpFontInfo(BOOL bDoLock)861 VOID DumpFontInfo(BOOL bDoLock)
862 {
863 DumpGlobalFontList(bDoLock);
864 DumpPrivateFontList(bDoLock);
865 DumpFontSubstList();
866 }
867 #endif
868
869 /*
870 * IntLoadFontSubstList --- loads the list of font substitutes
871 */
872 BOOL FASTCALL
IntLoadFontSubstList(PLIST_ENTRY pHead)873 IntLoadFontSubstList(PLIST_ENTRY pHead)
874 {
875 NTSTATUS Status;
876 HANDLE KeyHandle;
877 OBJECT_ATTRIBUTES ObjectAttributes;
878 KEY_FULL_INFORMATION KeyFullInfo;
879 ULONG i, Length;
880 UNICODE_STRING FromW, ToW;
881 BYTE InfoBuffer[128];
882 PKEY_VALUE_FULL_INFORMATION pInfo;
883 BYTE CharSets[FONTSUBST_FROM_AND_TO];
884 LPWSTR pch;
885 PFONTSUBST_ENTRY pEntry;
886
887 /* the FontSubstitutes registry key */
888 static UNICODE_STRING FontSubstKey =
889 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\"
890 L"Microsoft\\Windows NT\\CurrentVersion\\"
891 L"FontSubstitutes");
892
893 /* open registry key */
894 InitializeObjectAttributes(&ObjectAttributes, &FontSubstKey,
895 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
896 NULL, NULL);
897 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
898 if (!NT_SUCCESS(Status))
899 {
900 DPRINT("ZwOpenKey failed: 0x%08X\n", Status);
901 return FALSE; /* failure */
902 }
903
904 /* query count of values */
905 Status = ZwQueryKey(KeyHandle, KeyFullInformation,
906 &KeyFullInfo, sizeof(KeyFullInfo), &Length);
907 if (!NT_SUCCESS(Status))
908 {
909 DPRINT("ZwQueryKey failed: 0x%08X\n", Status);
910 ZwClose(KeyHandle);
911 return FALSE; /* failure */
912 }
913
914 /* for each value */
915 for (i = 0; i < KeyFullInfo.Values; ++i)
916 {
917 /* get value name */
918 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
919 InfoBuffer, sizeof(InfoBuffer), &Length);
920 if (!NT_SUCCESS(Status))
921 {
922 DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status);
923 break; /* failure */
924 }
925
926 /* create FromW string */
927 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
928 Length = pInfo->NameLength / sizeof(WCHAR);
929 pInfo->Name[Length] = UNICODE_NULL; /* truncate */
930 if (!RtlCreateUnicodeString(&FromW, pInfo->Name))
931 {
932 Status = STATUS_INSUFFICIENT_RESOURCES;
933 DPRINT("RtlCreateUnicodeString failed\n");
934 break; /* failure */
935 }
936
937 /* query value */
938 Status = ZwQueryValueKey(KeyHandle, &FromW, KeyValueFullInformation,
939 InfoBuffer, sizeof(InfoBuffer), &Length);
940 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
941 if (!NT_SUCCESS(Status) || !pInfo->DataLength)
942 {
943 DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status);
944 RtlFreeUnicodeString(&FromW);
945 break; /* failure */
946 }
947
948 /* create ToW string */
949 pch = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
950 Length = pInfo->DataLength / sizeof(WCHAR);
951 pch[Length] = UNICODE_NULL; /* truncate */
952 if (!RtlCreateUnicodeString(&ToW, pch))
953 {
954 Status = STATUS_INSUFFICIENT_RESOURCES;
955 DPRINT("RtlCreateUnicodeString failed\n");
956 RtlFreeUnicodeString(&FromW);
957 break; /* failure */
958 }
959
960 /* does charset exist? (from) */
961 CharSets[FONTSUBST_FROM] = DEFAULT_CHARSET;
962 pch = wcsrchr(FromW.Buffer, L',');
963 if (pch)
964 {
965 /* truncate */
966 *pch = UNICODE_NULL;
967 FromW.Length = (pch - FromW.Buffer) * sizeof(WCHAR);
968 /* parse charset number */
969 CharSets[FONTSUBST_FROM] = (BYTE)_wtoi(pch + 1);
970 }
971
972 /* does charset exist? (to) */
973 CharSets[FONTSUBST_TO] = DEFAULT_CHARSET;
974 pch = wcsrchr(ToW.Buffer, L',');
975 if (pch)
976 {
977 /* truncate */
978 *pch = UNICODE_NULL;
979 ToW.Length = (pch - ToW.Buffer) * sizeof(WCHAR);
980 /* parse charset number */
981 CharSets[FONTSUBST_TO] = (BYTE)_wtoi(pch + 1);
982 }
983
984 /* is it identical? */
985 if (RtlEqualUnicodeString(&FromW, &ToW, TRUE) &&
986 CharSets[FONTSUBST_FROM] == CharSets[FONTSUBST_TO])
987 {
988 RtlFreeUnicodeString(&FromW);
989 RtlFreeUnicodeString(&ToW);
990 continue;
991 }
992
993 /* allocate an entry */
994 pEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONTSUBST_ENTRY), TAG_FONT);
995 if (pEntry == NULL)
996 {
997 DPRINT("ExAllocatePoolWithTag failed\n");
998 RtlFreeUnicodeString(&FromW);
999 RtlFreeUnicodeString(&ToW);
1000 break; /* failure */
1001 }
1002
1003 /* store to *pEntry */
1004 pEntry->FontNames[FONTSUBST_FROM] = FromW;
1005 pEntry->FontNames[FONTSUBST_TO] = ToW;
1006 pEntry->CharSets[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
1007 pEntry->CharSets[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
1008
1009 /* insert pEntry to *pHead */
1010 InsertTailList(pHead, &pEntry->ListEntry);
1011 }
1012
1013 /* close now */
1014 ZwClose(KeyHandle);
1015
1016 return NT_SUCCESS(Status);
1017 }
1018
1019 BOOL FASTCALL
InitFontSupport(VOID)1020 InitFontSupport(VOID)
1021 {
1022 ULONG ulError;
1023
1024 g_FontCacheNumEntries = 0;
1025
1026 g_FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
1027 if (g_FreeTypeLock == NULL)
1028 {
1029 return FALSE;
1030 }
1031 ExInitializeFastMutex(g_FreeTypeLock);
1032
1033 ulError = FT_Init_FreeType(&g_FreeTypeLibrary);
1034 if (ulError)
1035 {
1036 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
1037 return FALSE;
1038 }
1039
1040 if (!IntLoadFontsInRegistry())
1041 {
1042 DPRINT1("Fonts registry is empty.\n");
1043
1044 /* Load font(s) with writing registry */
1045 IntLoadSystemFonts();
1046 }
1047
1048 IntLoadFontSubstList(&g_FontSubstListHead);
1049
1050 #if 0
1051 DumpFontInfo(TRUE);
1052 #endif
1053
1054 FontLink_LoadSettings();
1055 FontLink_LoadDefaultFonts();
1056 FontLink_LoadDefaultCharset();
1057
1058 return TRUE;
1059 }
1060
1061 VOID FASTCALL
FreeFontSupport(VOID)1062 FreeFontSupport(VOID)
1063 {
1064 PLIST_ENTRY pHead, pEntry;
1065 PFONT_CACHE_ENTRY pFontCache;
1066 PFONTSUBST_ENTRY pSubstEntry;
1067 PFONT_ENTRY pFontEntry;
1068
1069 // Cleanup the FontLink cache
1070 FontLink_CleanupCache();
1071
1072 // Free font cache list
1073 pHead = &g_FontCacheListHead;
1074 while (!IsListEmpty(pHead))
1075 {
1076 pEntry = RemoveHeadList(pHead);
1077 pFontCache = CONTAINING_RECORD(pEntry, FONT_CACHE_ENTRY, ListEntry);
1078 RemoveCachedEntry(pFontCache);
1079 }
1080
1081 // Free font subst list
1082 pHead = &g_FontSubstListHead;
1083 while (!IsListEmpty(pHead))
1084 {
1085 pEntry = RemoveHeadList(pHead);
1086 pSubstEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
1087 ExFreePoolWithTag(pSubstEntry, TAG_FONT);
1088 }
1089
1090 // Free font list
1091 pHead = &g_FontListHead;
1092 while (!IsListEmpty(pHead))
1093 {
1094 pEntry = RemoveHeadList(pHead);
1095 pFontEntry = CONTAINING_RECORD(pEntry, FONT_ENTRY, ListEntry);
1096 CleanupFontEntry(pFontEntry);
1097 }
1098
1099 if (g_FreeTypeLibrary)
1100 {
1101 FT_Done_Library(g_FreeTypeLibrary);
1102 g_FreeTypeLibrary = NULL;
1103 }
1104
1105 ExFreePoolWithTag(g_FreeTypeLock, TAG_INTERNAL_SYNC);
1106 g_FreeTypeLock = NULL;
1107 }
1108
IntNormalizeAngle(LONG nTenthsOfDegrees)1109 static LONG IntNormalizeAngle(LONG nTenthsOfDegrees)
1110 {
1111 nTenthsOfDegrees %= 360 * 10;
1112 if (nTenthsOfDegrees >= 0)
1113 return nTenthsOfDegrees;
1114 return nTenthsOfDegrees + 360 * 10;
1115 }
1116
IntEscapeMatrix(FT_Matrix * pmat,LONG lfEscapement)1117 static VOID FASTCALL IntEscapeMatrix(FT_Matrix *pmat, LONG lfEscapement)
1118 {
1119 FT_Vector vecAngle;
1120 /* Convert the angle in tenths of degrees into degrees as a 16.16 fixed-point value */
1121 FT_Angle angle = INT_TO_FIXED(lfEscapement) / 10;
1122 FT_Vector_Unit(&vecAngle, angle);
1123 pmat->xx = vecAngle.x;
1124 pmat->xy = -vecAngle.y;
1125 pmat->yx = -pmat->xy;
1126 pmat->yy = pmat->xx;
1127 }
1128
1129 static VOID FASTCALL
IntMatrixFromMx(FT_Matrix * pmat,const MATRIX * pmx)1130 IntMatrixFromMx(FT_Matrix *pmat, const MATRIX *pmx)
1131 {
1132 FLOATOBJ ef;
1133
1134 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
1135 ef = pmx->efM11;
1136 FLOATOBJ_MulLong(&ef, 0x00010000);
1137 pmat->xx = FLOATOBJ_GetLong(&ef);
1138
1139 ef = pmx->efM21;
1140 FLOATOBJ_MulLong(&ef, 0x00010000);
1141 pmat->xy = -FLOATOBJ_GetLong(&ef); /* (*1) See below */
1142
1143 ef = pmx->efM12;
1144 FLOATOBJ_MulLong(&ef, 0x00010000);
1145 pmat->yx = -FLOATOBJ_GetLong(&ef); /* (*1) See below */
1146
1147 ef = pmx->efM22;
1148 FLOATOBJ_MulLong(&ef, 0x00010000);
1149 pmat->yy = FLOATOBJ_GetLong(&ef);
1150
1151 // (*1): Y direction is mirrored as follows:
1152 //
1153 // [ M11 -M12 ] [ X ] [ M11*X + M12*Y ]
1154 // [ ] * [ ] == [ ]
1155 // [ -M21 M22 ] [ -Y ] [ -(M21*X + M22*Y) ].
1156 }
1157
1158 static BOOL
SubstituteFontByList(PLIST_ENTRY pHead,PUNICODE_STRING pOutputName,PUNICODE_STRING pInputName,BYTE RequestedCharSet,BYTE CharSetMap[FONTSUBST_FROM_AND_TO])1159 SubstituteFontByList(PLIST_ENTRY pHead,
1160 PUNICODE_STRING pOutputName,
1161 PUNICODE_STRING pInputName,
1162 BYTE RequestedCharSet,
1163 BYTE CharSetMap[FONTSUBST_FROM_AND_TO])
1164 {
1165 PLIST_ENTRY pListEntry;
1166 PFONTSUBST_ENTRY pSubstEntry;
1167 BYTE CharSets[FONTSUBST_FROM_AND_TO];
1168
1169 CharSetMap[FONTSUBST_FROM] = DEFAULT_CHARSET;
1170 CharSetMap[FONTSUBST_TO] = RequestedCharSet;
1171
1172 /* for each list entry */
1173 for (pListEntry = pHead->Flink;
1174 pListEntry != pHead;
1175 pListEntry = pListEntry->Flink)
1176 {
1177 pSubstEntry = CONTAINING_RECORD(pListEntry, FONTSUBST_ENTRY, ListEntry);
1178
1179 CharSets[FONTSUBST_FROM] = pSubstEntry->CharSets[FONTSUBST_FROM];
1180
1181 if (CharSets[FONTSUBST_FROM] != DEFAULT_CHARSET &&
1182 CharSets[FONTSUBST_FROM] != RequestedCharSet)
1183 {
1184 continue; /* not matched */
1185 }
1186
1187 /* does charset number exist? (to) */
1188 if (pSubstEntry->CharSets[FONTSUBST_TO] != DEFAULT_CHARSET)
1189 {
1190 CharSets[FONTSUBST_TO] = pSubstEntry->CharSets[FONTSUBST_TO];
1191 }
1192 else
1193 {
1194 CharSets[FONTSUBST_TO] = RequestedCharSet;
1195 }
1196
1197 /* does font name match? */
1198 if (!RtlEqualUnicodeString(&pSubstEntry->FontNames[FONTSUBST_FROM],
1199 pInputName, TRUE))
1200 {
1201 continue; /* not matched */
1202 }
1203
1204 /* update *pOutputName */
1205 *pOutputName = pSubstEntry->FontNames[FONTSUBST_TO];
1206
1207 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
1208 {
1209 /* update CharSetMap */
1210 CharSetMap[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
1211 CharSetMap[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
1212 }
1213 return TRUE; /* success */
1214 }
1215
1216 return FALSE;
1217 }
1218
1219 static VOID
IntUnicodeStringToBuffer(LPWSTR pszBuffer,SIZE_T cbBuffer,const UNICODE_STRING * pString)1220 IntUnicodeStringToBuffer(LPWSTR pszBuffer, SIZE_T cbBuffer, const UNICODE_STRING *pString)
1221 {
1222 SIZE_T cbLength = pString->Length;
1223
1224 if (cbBuffer < sizeof(UNICODE_NULL))
1225 return;
1226
1227 if (cbLength > cbBuffer - sizeof(UNICODE_NULL))
1228 cbLength = cbBuffer - sizeof(UNICODE_NULL);
1229
1230 RtlCopyMemory(pszBuffer, pString->Buffer, cbLength);
1231 pszBuffer[cbLength / sizeof(WCHAR)] = UNICODE_NULL;
1232 }
1233
1234 static NTSTATUS
DuplicateUnicodeString(PUNICODE_STRING Source,PUNICODE_STRING Destination)1235 DuplicateUnicodeString(PUNICODE_STRING Source, PUNICODE_STRING Destination)
1236 {
1237 NTSTATUS Status = STATUS_NO_MEMORY;
1238 UNICODE_STRING Tmp;
1239
1240 Tmp.Buffer = ExAllocatePoolWithTag(PagedPool, Source->MaximumLength, TAG_USTR);
1241 if (Tmp.Buffer)
1242 {
1243 Tmp.MaximumLength = Source->MaximumLength;
1244 Tmp.Length = 0;
1245 RtlCopyUnicodeString(&Tmp, Source);
1246
1247 Destination->MaximumLength = Tmp.MaximumLength;
1248 Destination->Length = Tmp.Length;
1249 Destination->Buffer = Tmp.Buffer;
1250
1251 Status = STATUS_SUCCESS;
1252 }
1253
1254 return Status;
1255 }
1256
1257 static BOOL
SubstituteFontRecurse(PLOGFONTW pLogFont)1258 SubstituteFontRecurse(PLOGFONTW pLogFont)
1259 {
1260 UINT RecurseCount = 5;
1261 UNICODE_STRING OutputNameW = { 0 };
1262 BYTE CharSetMap[FONTSUBST_FROM_AND_TO];
1263 BOOL Found;
1264 UNICODE_STRING InputNameW;
1265
1266 if (pLogFont->lfFaceName[0] == UNICODE_NULL)
1267 return FALSE;
1268
1269 RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
1270
1271 while (RecurseCount-- > 0)
1272 {
1273 Found = SubstituteFontByList(&g_FontSubstListHead,
1274 &OutputNameW, &InputNameW,
1275 pLogFont->lfCharSet, CharSetMap);
1276 if (!Found)
1277 break;
1278
1279 IntUnicodeStringToBuffer(pLogFont->lfFaceName, sizeof(pLogFont->lfFaceName), &OutputNameW);
1280 RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
1281
1282 if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
1283 CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
1284 {
1285 pLogFont->lfCharSet = CharSetMap[FONTSUBST_TO];
1286 }
1287 }
1288
1289 return TRUE; /* success */
1290 }
1291
1292 // Quickly initialize a FONTLINK_CHAIN
1293 static inline VOID
FontLink_Chain_Init(_Out_ PFONTLINK_CHAIN pChain,_Inout_ PTEXTOBJ pTextObj,_In_ FT_Face face)1294 FontLink_Chain_Init(
1295 _Out_ PFONTLINK_CHAIN pChain,
1296 _Inout_ PTEXTOBJ pTextObj,
1297 _In_ FT_Face face)
1298 {
1299 RtlZeroMemory(pChain, sizeof(*pChain));
1300 pChain->pBaseTextObj = pTextObj;
1301 pChain->pDefFace = face;
1302 ASSERT(!FontLink_Chain_IsPopulated(pChain));
1303 }
1304
1305 // The default FontLink data
1306 static const WCHAR s_szzDefFontLink[] =
1307 L"tahoma.ttf,Tahoma\0"
1308 L"msgothic.ttc,MS UI Gothic\0"
1309 L"mingliu.ttc,PMingLiU\0"
1310 L"simsun.ttc,SimSun\0"
1311 L"gulim.ttc,Gulim\0"
1312 L"\0";
1313 // The default fixed-pitch FontLink data
1314 static const WCHAR s_szzDefFixedFontLink[] =
1315 L"cour.ttf,Courier New\0"
1316 L"msgothic.ttc,MS Gothic\0"
1317 L"mingliu.ttc,MingLiU\0"
1318 L"simsun.ttc,NSimSun\0"
1319 L"gulim.ttc,GulimChe\0"
1320 L"\0";
1321
1322 static NTSTATUS
FontLink_Chain_LoadReg(_Inout_ PFONTLINK_CHAIN pChain,_Inout_ PLOGFONTW pLF)1323 FontLink_Chain_LoadReg(
1324 _Inout_ PFONTLINK_CHAIN pChain,
1325 _Inout_ PLOGFONTW pLF)
1326 {
1327 NTSTATUS Status;
1328 HKEY hKey;
1329 DWORD cbData;
1330 WCHAR szzFontLink[512];
1331 SIZE_T FontLinkSize;
1332 PZZWSTR pszzFontLink = NULL;
1333
1334 ASSERT(pLF->lfFaceName[0]);
1335
1336 // Open the registry key
1337 Status = RegOpenKey(
1338 L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink",
1339 &hKey);
1340 if (!NT_SUCCESS(Status))
1341 return Status;
1342
1343 // Load the FontLink entry
1344 cbData = sizeof(szzFontLink);
1345 Status = RegQueryValue(hKey, pLF->lfFaceName, REG_MULTI_SZ, szzFontLink, &cbData);
1346 if (!NT_SUCCESS(Status) &&
1347 (Status != STATUS_BUFFER_OVERFLOW) && (Status != STATUS_BUFFER_TOO_SMALL))
1348 {
1349 // Retry with substituted
1350 SubstituteFontRecurse(pLF);
1351 cbData = sizeof(szzFontLink);
1352 Status = RegQueryValue(hKey, pLF->lfFaceName, REG_MULTI_SZ, szzFontLink, &cbData);
1353 }
1354
1355 if ((Status == STATUS_BUFFER_OVERFLOW) || (Status == STATUS_BUFFER_TOO_SMALL))
1356 {
1357 // Buffer is too small. Retry with larger buffer
1358 if (cbData >= 2 * sizeof(WCHAR)) // Sanity check
1359 {
1360 FontLinkSize = cbData;
1361 pszzFontLink = ExAllocatePoolWithTag(PagedPool, FontLinkSize, TAG_FONT);
1362 if (!pszzFontLink)
1363 {
1364 ZwClose(hKey); // Close the registry key
1365 return STATUS_NO_MEMORY;
1366 }
1367 Status = RegQueryValue(hKey, pLF->lfFaceName, REG_MULTI_SZ, pszzFontLink, &cbData);
1368 if (!NT_SUCCESS(Status))
1369 {
1370 ExFreePoolWithTag(pszzFontLink, TAG_FONT);
1371 pszzFontLink = NULL;
1372 }
1373 }
1374 }
1375
1376 ZwClose(hKey); // Close the registry key
1377
1378 if (!NT_SUCCESS(Status)) // Failed to get registry value
1379 {
1380 // Use default value
1381 ASSERT(sizeof(szzFontLink) >= sizeof(s_szzDefFontLink));
1382 ASSERT(sizeof(szzFontLink) >= sizeof(s_szzDefFixedFontLink));
1383 if (!(pLF->lfPitchAndFamily & FIXED_PITCH))
1384 RtlCopyMemory(szzFontLink, s_szzDefFontLink, sizeof(s_szzDefFontLink));
1385 else
1386 RtlCopyMemory(szzFontLink, s_szzDefFixedFontLink, sizeof(s_szzDefFixedFontLink));
1387 }
1388
1389 if (pszzFontLink)
1390 {
1391 // Ensure double-NUL-terminated
1392 ASSERT(FontLinkSize / sizeof(WCHAR) >= 2);
1393 pszzFontLink[FontLinkSize / sizeof(WCHAR) - 1] = UNICODE_NULL;
1394 pszzFontLink[FontLinkSize / sizeof(WCHAR) - 2] = UNICODE_NULL;
1395 }
1396 else
1397 {
1398 // Ensure double-NUL-terminated
1399 szzFontLink[_countof(szzFontLink) - 1] = UNICODE_NULL;
1400 szzFontLink[_countof(szzFontLink) - 2] = UNICODE_NULL;
1401
1402 FontLinkSize = SZZ_GetSize(szzFontLink);
1403 pszzFontLink = ExAllocatePoolWithTag(PagedPool, FontLinkSize, TAG_FONT);
1404 if (!pszzFontLink)
1405 return STATUS_NO_MEMORY;
1406 RtlCopyMemory(pszzFontLink, szzFontLink, FontLinkSize);
1407 }
1408 pChain->pszzFontLink = pszzFontLink;
1409
1410 return STATUS_SUCCESS;
1411 }
1412
1413 static inline PFONTLINK
FontLink_Chain_FindLink(PFONTLINK_CHAIN pChain,PLOGFONTW plf)1414 FontLink_Chain_FindLink(
1415 PFONTLINK_CHAIN pChain,
1416 PLOGFONTW plf)
1417 {
1418 PLIST_ENTRY Entry, Head = &pChain->FontLinkList;
1419 PFONTLINK pLink;
1420
1421 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
1422 {
1423 pLink = CONTAINING_RECORD(Entry, FONTLINK, ListEntry);
1424 if (RtlEqualMemory(&pLink->LogFont, plf, sizeof(*plf)))
1425 return pLink;
1426 }
1427
1428 return NULL;
1429 }
1430
1431 static inline PFONTLINK
FontLink_Create(_Inout_ PFONTLINK_CHAIN pChain,_In_ const LOGFONTW * plfBase,_In_ LPCWSTR pszLink)1432 FontLink_Create(
1433 _Inout_ PFONTLINK_CHAIN pChain,
1434 _In_ const LOGFONTW *plfBase,
1435 _In_ LPCWSTR pszLink)
1436 {
1437 LPWSTR pch0, pch1;
1438 LOGFONTW lf;
1439 PFONTLINK pLink;
1440
1441 lf = *plfBase;
1442
1443 // pszLink: "<FontFileName>,<FaceName>[,...]"
1444 pch0 = wcschr(pszLink, L',');
1445 if (!pch0)
1446 {
1447 DPRINT1("%S\n", pszLink);
1448 return NULL; // Invalid FontLink data
1449 }
1450 ++pch0;
1451
1452 pch1 = wcschr(pch0, L',');
1453 if (pch1)
1454 RtlStringCchCopyNW(lf.lfFaceName, _countof(lf.lfFaceName), pch0, pch1 - pch0);
1455 else
1456 RtlStringCchCopyW(lf.lfFaceName, _countof(lf.lfFaceName), pch0);
1457
1458 SubstituteFontRecurse(&lf);
1459 DPRINT("lfFaceName: %S\n", lf.lfFaceName);
1460
1461 if (RtlEqualMemory(plfBase, &lf, sizeof(lf)) || FontLink_Chain_FindLink(pChain, &lf))
1462 return NULL; // Already exists
1463
1464 pLink = ExAllocatePoolZero(PagedPool, sizeof(FONTLINK), TAG_FONT);
1465 if (!pLink)
1466 return NULL; // Out of memory
1467
1468 pLink->LogFont = lf;
1469 return pLink;
1470 }
1471
1472 static NTSTATUS
FontLink_Chain_Populate(_Inout_ PFONTLINK_CHAIN pChain)1473 FontLink_Chain_Populate(
1474 _Inout_ PFONTLINK_CHAIN pChain)
1475 {
1476 NTSTATUS Status;
1477 PFONTLINK pLink;
1478 LOGFONTW lfBase;
1479 PTEXTOBJ pTextObj = pChain->pBaseTextObj;
1480 PFONTGDI pFontGDI;
1481 PWSTR pszLink;
1482 PFONTLINK_CACHE pLinkCache;
1483 WCHAR szEntry[MAX_PATH];
1484 BOOL bFixCharSet;
1485
1486 InitializeListHead(&pChain->FontLinkList);
1487
1488 lfBase = pTextObj->logfont.elfEnumLogfontEx.elfLogFont;
1489 pFontGDI = ObjToGDI(pTextObj->Font, FONT);
1490 lfBase.lfHeight = pFontGDI->lfHeight;
1491 lfBase.lfWidth = pFontGDI->lfWidth;
1492
1493 // Use pTextObj->TextFace if lfFaceName was empty
1494 if (!lfBase.lfFaceName[0])
1495 {
1496 ASSERT(pTextObj->TextFace[0]);
1497 RtlStringCchCopyW(lfBase.lfFaceName, _countof(lfBase.lfFaceName), pTextObj->TextFace);
1498 }
1499
1500 // Fix lfCharSet
1501 switch (lfBase.lfCharSet)
1502 {
1503 case ANSI_CHARSET: bFixCharSet = !s_fFontLinkUseAnsi; break;
1504 case OEM_CHARSET: bFixCharSet = !s_fFontLinkUseOem; break;
1505 case SYMBOL_CHARSET: bFixCharSet = !s_fFontLinkUseSymbol; break;
1506 default: bFixCharSet = TRUE; break;
1507 }
1508 if (bFixCharSet)
1509 lfBase.lfCharSet = DEFAULT_CHARSET;
1510
1511 // Use cache if any
1512 pLinkCache = FontLink_FindCache(&lfBase);
1513 if (pLinkCache)
1514 {
1515 RemoveEntryList(&pLinkCache->ListEntry);
1516 *pChain = pLinkCache->Chain;
1517 IntRebaseList(&pChain->FontLinkList, &pLinkCache->Chain.FontLinkList);
1518 ExFreePoolWithTag(pLinkCache, TAG_FONT);
1519 return STATUS_SUCCESS;
1520 }
1521
1522 pChain->LogFont = lfBase;
1523
1524 // Load FontLink entry from registry
1525 Status = FontLink_Chain_LoadReg(pChain, &pChain->LogFont);
1526 if (!NT_SUCCESS(Status))
1527 return Status;
1528
1529 pszLink = pChain->pszzFontLink;
1530 while (*pszLink)
1531 {
1532 DPRINT("pszLink: '%S'\n", pszLink);
1533 pLink = FontLink_Create(pChain, &lfBase, pszLink);
1534 if (pLink)
1535 InsertTailList(&pChain->FontLinkList, &pLink->ListEntry);
1536 pszLink += wcslen(pszLink) + 1;
1537 }
1538
1539 // Use default settings (if any)
1540 if (s_szDefFontLinkFileName[0] && s_szDefFontLinkFontName[0])
1541 {
1542 RtlStringCchCopyW(szEntry, _countof(szEntry), s_szDefFontLinkFileName);
1543 RtlStringCchCatW(szEntry, _countof(szEntry), L",");
1544 RtlStringCchCatW(szEntry, _countof(szEntry), s_szDefFontLinkFontName);
1545 DPRINT("szEntry: '%S'\n", szEntry);
1546 pLink = FontLink_Create(pChain, &lfBase, szEntry);
1547 if (pLink)
1548 InsertTailList(&pChain->FontLinkList, &pLink->ListEntry);
1549 }
1550
1551 ASSERT(FontLink_Chain_IsPopulated(pChain));
1552 return Status;
1553 }
1554
1555 /*
1556 * IntLoadSystemFonts
1557 *
1558 * Search the system font directory and adds each font found.
1559 */
1560 VOID FASTCALL
IntLoadSystemFonts(VOID)1561 IntLoadSystemFonts(VOID)
1562 {
1563 OBJECT_ATTRIBUTES ObjectAttributes;
1564 UNICODE_STRING Directory, FileName, TempString;
1565 IO_STATUS_BLOCK Iosb;
1566 HANDLE hDirectory;
1567 BYTE *DirInfoBuffer;
1568 PFILE_DIRECTORY_INFORMATION DirInfo;
1569 BOOLEAN bRestartScan = TRUE;
1570 NTSTATUS Status;
1571 INT i;
1572 static UNICODE_STRING SearchPatterns[] =
1573 {
1574 RTL_CONSTANT_STRING(L"*.ttf"),
1575 RTL_CONSTANT_STRING(L"*.ttc"),
1576 RTL_CONSTANT_STRING(L"*.otf"),
1577 RTL_CONSTANT_STRING(L"*.otc"),
1578 RTL_CONSTANT_STRING(L"*.fon"),
1579 RTL_CONSTANT_STRING(L"*.fnt")
1580 };
1581 static UNICODE_STRING IgnoreFiles[] =
1582 {
1583 RTL_CONSTANT_STRING(L"."),
1584 RTL_CONSTANT_STRING(L".."),
1585 };
1586
1587 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
1588
1589 InitializeObjectAttributes(
1590 &ObjectAttributes,
1591 &Directory,
1592 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1593 NULL,
1594 NULL);
1595
1596 Status = ZwOpenFile(
1597 &hDirectory,
1598 SYNCHRONIZE | FILE_LIST_DIRECTORY,
1599 &ObjectAttributes,
1600 &Iosb,
1601 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1602 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
1603
1604 if (NT_SUCCESS(Status))
1605 {
1606 for (i = 0; i < _countof(SearchPatterns); ++i)
1607 {
1608 DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
1609 if (DirInfoBuffer == NULL)
1610 {
1611 ZwClose(hDirectory);
1612 return;
1613 }
1614
1615 FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
1616 if (FileName.Buffer == NULL)
1617 {
1618 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
1619 ZwClose(hDirectory);
1620 return;
1621 }
1622 FileName.Length = 0;
1623 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
1624
1625 while (1)
1626 {
1627 Status = ZwQueryDirectoryFile(
1628 hDirectory,
1629 NULL,
1630 NULL,
1631 NULL,
1632 &Iosb,
1633 DirInfoBuffer,
1634 0x4000,
1635 FileDirectoryInformation,
1636 FALSE,
1637 &SearchPatterns[i],
1638 bRestartScan);
1639
1640 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
1641 {
1642 break;
1643 }
1644
1645 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
1646 while (1)
1647 {
1648 SIZE_T ign;
1649
1650 TempString.Buffer = DirInfo->FileName;
1651 TempString.Length = TempString.MaximumLength = DirInfo->FileNameLength;
1652
1653 /* Should we ignore this file? */
1654 for (ign = 0; ign < _countof(IgnoreFiles); ++ign)
1655 {
1656 /* Yes.. */
1657 if (RtlEqualUnicodeString(IgnoreFiles + ign, &TempString, FALSE))
1658 break;
1659 }
1660
1661 /* If we tried all Ignore patterns and there was no match, try to create a font */
1662 if (ign == _countof(IgnoreFiles))
1663 {
1664 RtlCopyUnicodeString(&FileName, &Directory);
1665 RtlAppendUnicodeStringToString(&FileName, &TempString);
1666 if (!IntGdiAddFontResourceEx(&FileName, 0, AFRX_WRITE_REGISTRY))
1667 {
1668 DPRINT1("ERR: Failed to load %wZ\n", &FileName);
1669 }
1670 }
1671
1672 if (DirInfo->NextEntryOffset == 0)
1673 break;
1674
1675 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
1676 }
1677
1678 bRestartScan = FALSE;
1679 }
1680
1681 ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
1682 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
1683 }
1684 ZwClose(hDirectory);
1685 }
1686 }
1687
1688 /* NOTE: If nIndex < 0 then return the number of charsets. */
IntGetCharSet(INT nIndex,FT_ULong CodePageRange1)1689 UINT FASTCALL IntGetCharSet(INT nIndex, FT_ULong CodePageRange1)
1690 {
1691 UINT BitIndex, CharSet;
1692 UINT nCount = 0;
1693
1694 if (CodePageRange1 == 0)
1695 {
1696 return (nIndex < 0) ? 1 : DEFAULT_CHARSET;
1697 }
1698
1699 for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
1700 {
1701 if (CodePageRange1 & (1 << BitIndex))
1702 {
1703 CharSet = g_FontTci[BitIndex].ciCharset;
1704 if ((nIndex >= 0) && (nCount == (UINT)nIndex))
1705 {
1706 return CharSet;
1707 }
1708 ++nCount;
1709 }
1710 }
1711
1712 return (nIndex < 0) ? nCount : ANSI_CHARSET;
1713 }
1714
1715 /* pixels to points */
1716 #define PX2PT(pixels) FT_MulDiv((pixels), 72, 96)
1717
1718 static INT FASTCALL
IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,PSHARED_FACE SharedFace,FT_Long FontIndex,INT CharSetIndex)1719 IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
1720 PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
1721 {
1722 FT_Error Error;
1723 PFONT_ENTRY Entry;
1724 FONT_ENTRY_MEM* PrivateEntry = NULL;
1725 FONTGDI * FontGDI;
1726 NTSTATUS Status;
1727 FT_Face Face;
1728 ANSI_STRING AnsiString;
1729 FT_WinFNT_HeaderRec WinFNT;
1730 INT FaceCount = 0, CharSetCount = 0;
1731 PUNICODE_STRING pFileName = pLoadFont->pFileName;
1732 DWORD Characteristics = pLoadFont->Characteristics;
1733 PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
1734 TT_OS2 * pOS2;
1735 INT BitIndex;
1736 FT_UShort os2_version;
1737 FT_ULong os2_ulCodePageRange1;
1738 FT_UShort os2_usWeightClass;
1739
1740 if (SharedFace == NULL && CharSetIndex == -1)
1741 {
1742 /* load a face from memory */
1743 IntLockFreeType();
1744 Error = FT_New_Memory_Face(
1745 g_FreeTypeLibrary,
1746 pLoadFont->Memory->Buffer,
1747 pLoadFont->Memory->BufferSize,
1748 ((FontIndex != -1) ? FontIndex : 0),
1749 &Face);
1750
1751 if (!Error)
1752 SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
1753
1754 IntUnLockFreeType();
1755
1756 if (!Error && FT_IS_SFNT(Face))
1757 pLoadFont->IsTrueType = TRUE;
1758
1759 if (Error || SharedFace == NULL)
1760 {
1761 if (SharedFace)
1762 SharedFace_Release(SharedFace);
1763
1764 if (Error == FT_Err_Unknown_File_Format)
1765 DPRINT1("Unknown font file format\n");
1766 else
1767 DPRINT1("Error reading font (error code: %d)\n", Error);
1768 return 0; /* failure */
1769 }
1770 }
1771 else
1772 {
1773 Face = SharedFace->Face;
1774 IntLockFreeType();
1775 SharedFace_AddRef(SharedFace);
1776 IntUnLockFreeType();
1777 }
1778
1779 /* allocate a FONT_ENTRY */
1780 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
1781 if (!Entry)
1782 {
1783 SharedFace_Release(SharedFace);
1784 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1785 return 0; /* failure */
1786 }
1787
1788 /* allocate a FONTGDI */
1789 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
1790 if (!FontGDI)
1791 {
1792 SharedFace_Release(SharedFace);
1793 ExFreePoolWithTag(Entry, TAG_FONT);
1794 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1795 return 0; /* failure */
1796 }
1797
1798 /* set file name */
1799 if (pFileName)
1800 {
1801 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool,
1802 pFileName->Length + sizeof(UNICODE_NULL),
1803 GDITAG_PFF);
1804 if (FontGDI->Filename == NULL)
1805 {
1806 EngFreeMem(FontGDI);
1807 SharedFace_Release(SharedFace);
1808 ExFreePoolWithTag(Entry, TAG_FONT);
1809 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1810 return 0; /* failure */
1811 }
1812
1813 RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
1814 FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1815 }
1816 else
1817 {
1818 FontGDI->Filename = NULL;
1819
1820 PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT);
1821 if (!PrivateEntry)
1822 {
1823 if (FontGDI->Filename)
1824 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1825 EngFreeMem(FontGDI);
1826 SharedFace_Release(SharedFace);
1827 ExFreePoolWithTag(Entry, TAG_FONT);
1828 return 0;
1829 }
1830
1831 PrivateEntry->Entry = Entry;
1832 if (pLoadFont->PrivateEntry)
1833 {
1834 InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry);
1835 }
1836 else
1837 {
1838 InitializeListHead(&PrivateEntry->ListEntry);
1839 pLoadFont->PrivateEntry = PrivateEntry;
1840 }
1841 }
1842
1843 /* set face */
1844 FontGDI->SharedFace = SharedFace;
1845 FontGDI->CharSet = ANSI_CHARSET;
1846 FontGDI->OriginalItalic = FALSE;
1847 FontGDI->RequestItalic = FALSE;
1848 FontGDI->OriginalWeight = FALSE;
1849 FontGDI->RequestWeight = FW_NORMAL;
1850
1851 IntLockFreeType();
1852 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
1853 if (pOS2)
1854 {
1855 FontGDI->OriginalItalic = !!(pOS2->fsSelection & 0x1);
1856 FontGDI->OriginalWeight = pOS2->usWeightClass;
1857 }
1858 else
1859 {
1860 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
1861 if (!Error)
1862 {
1863 FontGDI->OriginalItalic = !!WinFNT.italic;
1864 FontGDI->OriginalWeight = WinFNT.weight;
1865 }
1866 }
1867 IntUnLockFreeType();
1868
1869 RtlInitAnsiString(&AnsiString, Face->family_name);
1870 Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiString, TRUE);
1871 if (NT_SUCCESS(Status))
1872 {
1873 if (Face->style_name && Face->style_name[0] &&
1874 strcmp(Face->style_name, "Regular") != 0)
1875 {
1876 RtlInitAnsiString(&AnsiString, Face->style_name);
1877 Status = RtlAnsiStringToUnicodeString(&Entry->StyleName, &AnsiString, TRUE);
1878 if (!NT_SUCCESS(Status))
1879 {
1880 RtlFreeUnicodeString(&Entry->FaceName);
1881 }
1882 }
1883 else
1884 {
1885 RtlInitUnicodeString(&Entry->StyleName, NULL);
1886 }
1887 }
1888 if (!NT_SUCCESS(Status))
1889 {
1890 if (PrivateEntry)
1891 {
1892 if (pLoadFont->PrivateEntry == PrivateEntry)
1893 {
1894 pLoadFont->PrivateEntry = NULL;
1895 }
1896 else
1897 {
1898 RemoveEntryList(&PrivateEntry->ListEntry);
1899 }
1900 ExFreePoolWithTag(PrivateEntry, TAG_FONT);
1901 }
1902 if (FontGDI->Filename)
1903 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1904 EngFreeMem(FontGDI);
1905 SharedFace_Release(SharedFace);
1906 ExFreePoolWithTag(Entry, TAG_FONT);
1907 return 0;
1908 }
1909
1910 os2_version = 0;
1911 IntLockFreeType();
1912 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
1913 if (pOS2)
1914 {
1915 os2_version = pOS2->version;
1916 os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
1917 os2_usWeightClass = pOS2->usWeightClass;
1918 }
1919 IntUnLockFreeType();
1920
1921 if (pOS2 && os2_version >= 1)
1922 {
1923 /* get charset and weight from OS/2 header */
1924
1925 /* Make sure we do not use this pointer anymore */
1926 pOS2 = NULL;
1927
1928 for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
1929 {
1930 if (os2_ulCodePageRange1 & (1 << BitIndex))
1931 {
1932 if (g_FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
1933 continue;
1934
1935 if ((CharSetIndex == -1 && CharSetCount == 0) ||
1936 CharSetIndex == CharSetCount)
1937 {
1938 FontGDI->CharSet = g_FontTci[BitIndex].ciCharset;
1939 }
1940
1941 ++CharSetCount;
1942 }
1943 }
1944
1945 /* set actual weight */
1946 FontGDI->OriginalWeight = os2_usWeightClass;
1947 }
1948 else
1949 {
1950 /* get charset from WinFNT header */
1951 IntLockFreeType();
1952 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
1953 if (!Error)
1954 {
1955 FontGDI->CharSet = WinFNT.charset;
1956 }
1957 IntUnLockFreeType();
1958 }
1959
1960 ++FaceCount;
1961 DPRINT("Font loaded: %s (%s)\n",
1962 Face->family_name ? Face->family_name : "<NULL>",
1963 Face->style_name ? Face->style_name : "<NULL>");
1964 DPRINT("Num glyphs: %d\n", Face->num_glyphs);
1965 DPRINT("CharSet: %d\n", FontGDI->CharSet);
1966
1967 /* Add this font resource to the font table */
1968 Entry->Font = FontGDI;
1969 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
1970
1971 IntLockFreeType();
1972 if (Characteristics & FR_PRIVATE)
1973 {
1974 /* private font */
1975 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1976 IntLockProcessPrivateFonts(Win32Process);
1977 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
1978 IntUnLockProcessPrivateFonts(Win32Process);
1979 }
1980 else
1981 {
1982 /* global font */
1983 InsertTailList(&g_FontListHead, &Entry->ListEntry);
1984 }
1985 IntUnLockFreeType();
1986
1987 if (FontIndex == -1)
1988 {
1989 if (FT_IS_SFNT(Face))
1990 {
1991 TT_Face TrueType = (TT_Face)Face;
1992 if (TrueType->ttc_header.count > 1)
1993 {
1994 FT_Long i;
1995 for (i = 1; i < TrueType->ttc_header.count; ++i)
1996 {
1997 FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
1998 }
1999 }
2000 }
2001 FontIndex = 0;
2002 }
2003
2004 if (CharSetIndex == -1)
2005 {
2006 INT i;
2007 USHORT NameLength = Entry->FaceName.Length;
2008
2009 if (Entry->StyleName.Length)
2010 NameLength += Entry->StyleName.Length + sizeof(WCHAR);
2011
2012 if (pLoadFont->RegValueName.Length == 0)
2013 {
2014 pValueName->Length = 0;
2015 pValueName->MaximumLength = NameLength + sizeof(WCHAR);
2016 pValueName->Buffer = ExAllocatePoolWithTag(PagedPool,
2017 pValueName->MaximumLength,
2018 TAG_USTR);
2019 pValueName->Buffer[0] = UNICODE_NULL;
2020 RtlAppendUnicodeStringToString(pValueName, &Entry->FaceName);
2021 }
2022 else
2023 {
2024 UNICODE_STRING NewString;
2025 USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + NameLength;
2026 NewString.Length = 0;
2027 NewString.MaximumLength = Length + sizeof(WCHAR);
2028 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
2029 NewString.MaximumLength,
2030 TAG_USTR);
2031 NewString.Buffer[0] = UNICODE_NULL;
2032
2033 RtlAppendUnicodeStringToString(&NewString, pValueName);
2034 RtlAppendUnicodeToString(&NewString, L" & ");
2035 RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
2036
2037 RtlFreeUnicodeString(pValueName);
2038 *pValueName = NewString;
2039 }
2040 if (Entry->StyleName.Length)
2041 {
2042 RtlAppendUnicodeToString(pValueName, L" ");
2043 RtlAppendUnicodeStringToString(pValueName, &Entry->StyleName);
2044 }
2045
2046 for (i = 1; i < CharSetCount; ++i)
2047 {
2048 /* Do not count charsets towards 'faces' loaded */
2049 IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
2050 }
2051 }
2052
2053 return FaceCount; /* number of loaded faces */
2054 }
2055
2056 static LPCWSTR FASTCALL
NameFromCharSet(BYTE CharSet)2057 NameFromCharSet(BYTE CharSet)
2058 {
2059 switch (CharSet)
2060 {
2061 case ANSI_CHARSET: return L"ANSI";
2062 case DEFAULT_CHARSET: return L"Default";
2063 case SYMBOL_CHARSET: return L"Symbol";
2064 case SHIFTJIS_CHARSET: return L"Shift_JIS";
2065 case HANGUL_CHARSET: return L"Hangul";
2066 case GB2312_CHARSET: return L"GB 2312";
2067 case CHINESEBIG5_CHARSET: return L"Chinese Big5";
2068 case OEM_CHARSET: return L"OEM";
2069 case JOHAB_CHARSET: return L"Johab";
2070 case HEBREW_CHARSET: return L"Hebrew";
2071 case ARABIC_CHARSET: return L"Arabic";
2072 case GREEK_CHARSET: return L"Greek";
2073 case TURKISH_CHARSET: return L"Turkish";
2074 case VIETNAMESE_CHARSET: return L"Vietnamese";
2075 case THAI_CHARSET: return L"Thai";
2076 case EASTEUROPE_CHARSET: return L"Eastern European";
2077 case RUSSIAN_CHARSET: return L"Russian";
2078 case MAC_CHARSET: return L"Mac";
2079 case BALTIC_CHARSET: return L"Baltic";
2080 default: return L"Unknown";
2081 }
2082 }
2083
2084 /*
2085 * IntGdiAddFontResource
2086 *
2087 * Adds the font resource from the specified file to the system.
2088 */
2089
2090 INT FASTCALL
IntGdiAddFontResourceEx(PUNICODE_STRING FileName,DWORD Characteristics,DWORD dwFlags)2091 IntGdiAddFontResourceEx(PUNICODE_STRING FileName, DWORD Characteristics,
2092 DWORD dwFlags)
2093 {
2094 NTSTATUS Status;
2095 HANDLE FileHandle;
2096 PVOID Buffer = NULL;
2097 IO_STATUS_BLOCK Iosb;
2098 PVOID SectionObject;
2099 SIZE_T ViewSize = 0, Length;
2100 LARGE_INTEGER SectionSize;
2101 OBJECT_ATTRIBUTES ObjectAttributes;
2102 GDI_LOAD_FONT LoadFont;
2103 INT FontCount;
2104 HANDLE KeyHandle;
2105 UNICODE_STRING PathName;
2106 LPWSTR pszBuffer;
2107 PFILE_OBJECT FileObject;
2108 static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
2109 static const UNICODE_STRING DosPathPrefix = RTL_CONSTANT_STRING(L"\\??\\");
2110
2111 /* Build PathName */
2112 if (dwFlags & AFRX_DOS_DEVICE_PATH)
2113 {
2114 Length = DosPathPrefix.Length + FileName->Length + sizeof(UNICODE_NULL);
2115 pszBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_USTR);
2116 if (!pszBuffer)
2117 return 0; /* failure */
2118
2119 RtlInitEmptyUnicodeString(&PathName, pszBuffer, Length);
2120 RtlAppendUnicodeStringToString(&PathName, &DosPathPrefix);
2121 RtlAppendUnicodeStringToString(&PathName, FileName);
2122 }
2123 else
2124 {
2125 Status = DuplicateUnicodeString(FileName, &PathName);
2126 if (!NT_SUCCESS(Status))
2127 return 0; /* failure */
2128 }
2129
2130 /* Open the font file */
2131 InitializeObjectAttributes(&ObjectAttributes, &PathName,
2132 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
2133 Status = ZwOpenFile(
2134 &FileHandle,
2135 FILE_GENERIC_READ | SYNCHRONIZE,
2136 &ObjectAttributes,
2137 &Iosb,
2138 FILE_SHARE_READ,
2139 FILE_SYNCHRONOUS_IO_NONALERT);
2140 if (!NT_SUCCESS(Status))
2141 {
2142 DPRINT1("Could not load font file: %wZ\n", &PathName);
2143 RtlFreeUnicodeString(&PathName);
2144 return 0;
2145 }
2146
2147 Status = ObReferenceObjectByHandle(FileHandle, FILE_READ_DATA, NULL,
2148 KernelMode, (PVOID*)&FileObject, NULL);
2149 if (!NT_SUCCESS(Status))
2150 {
2151 DPRINT1("ObReferenceObjectByHandle failed.\n");
2152 ZwClose(FileHandle);
2153 RtlFreeUnicodeString(&PathName);
2154 return 0;
2155 }
2156
2157 SectionSize.QuadPart = 0LL;
2158 Status = MmCreateSection(&SectionObject,
2159 STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
2160 NULL, &SectionSize, PAGE_READONLY,
2161 SEC_COMMIT, FileHandle, FileObject);
2162 if (!NT_SUCCESS(Status))
2163 {
2164 DPRINT1("Could not map file: %wZ\n", &PathName);
2165 ZwClose(FileHandle);
2166 ObDereferenceObject(FileObject);
2167 RtlFreeUnicodeString(&PathName);
2168 return 0;
2169 }
2170 ZwClose(FileHandle);
2171
2172 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
2173 if (!NT_SUCCESS(Status))
2174 {
2175 DPRINT1("Could not map file: %wZ\n", &PathName);
2176 ObDereferenceObject(SectionObject);
2177 ObDereferenceObject(FileObject);
2178 RtlFreeUnicodeString(&PathName);
2179 return 0;
2180 }
2181
2182 LoadFont.pFileName = &PathName;
2183 LoadFont.Memory = SharedMem_Create(Buffer, ViewSize, TRUE);
2184 LoadFont.Characteristics = Characteristics;
2185 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
2186 LoadFont.IsTrueType = FALSE;
2187 LoadFont.CharSet = DEFAULT_CHARSET;
2188 LoadFont.PrivateEntry = NULL;
2189 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
2190
2191 /* Release our copy */
2192 IntLockFreeType();
2193 SharedMem_Release(LoadFont.Memory);
2194 IntUnLockFreeType();
2195
2196 ObDereferenceObject(SectionObject);
2197
2198 ObDereferenceObject(FileObject);
2199
2200 /* Save the loaded font name into the registry */
2201 if (FontCount > 0 && (dwFlags & AFRX_WRITE_REGISTRY))
2202 {
2203 UNICODE_STRING NewString;
2204 SIZE_T Length;
2205 PWCHAR pszBuffer;
2206 LPCWSTR CharSetName;
2207 if (LoadFont.IsTrueType)
2208 {
2209 /* Append " (TrueType)" */
2210 Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length + sizeof(UNICODE_NULL);
2211 pszBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_USTR);
2212 if (pszBuffer)
2213 {
2214 RtlInitEmptyUnicodeString(&NewString, pszBuffer, Length);
2215 NewString.Buffer[0] = UNICODE_NULL;
2216 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
2217 RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
2218 RtlFreeUnicodeString(&LoadFont.RegValueName);
2219 LoadFont.RegValueName = NewString;
2220 }
2221 else
2222 {
2223 // FIXME!
2224 }
2225 }
2226 else if (LoadFont.CharSet != DEFAULT_CHARSET)
2227 {
2228 /* Append " (CharSetName)" */
2229 CharSetName = NameFromCharSet(LoadFont.CharSet);
2230 Length = LoadFont.RegValueName.Length +
2231 (wcslen(CharSetName) + 3) * sizeof(WCHAR) +
2232 sizeof(UNICODE_NULL);
2233
2234 pszBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_USTR);
2235 if (pszBuffer)
2236 {
2237 RtlInitEmptyUnicodeString(&NewString, pszBuffer, Length);
2238 NewString.Buffer[0] = UNICODE_NULL;
2239 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
2240 RtlAppendUnicodeToString(&NewString, L" (");
2241 RtlAppendUnicodeToString(&NewString, CharSetName);
2242 RtlAppendUnicodeToString(&NewString, L")");
2243 RtlFreeUnicodeString(&LoadFont.RegValueName);
2244 LoadFont.RegValueName = NewString;
2245 }
2246 else
2247 {
2248 // FIXME!
2249 }
2250 }
2251
2252 InitializeObjectAttributes(&ObjectAttributes, &g_FontRegPath,
2253 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2254 NULL, NULL);
2255 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
2256 if (NT_SUCCESS(Status))
2257 {
2258 SIZE_T DataSize;
2259 LPWSTR pFileName;
2260
2261 if (dwFlags & AFRX_ALTERNATIVE_PATH)
2262 {
2263 pFileName = PathName.Buffer;
2264 }
2265 else
2266 {
2267 pFileName = wcsrchr(PathName.Buffer, L'\\');
2268 }
2269
2270 if (pFileName)
2271 {
2272 if (!(dwFlags & AFRX_ALTERNATIVE_PATH))
2273 {
2274 pFileName++;
2275 }
2276 DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
2277 ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
2278 pFileName, DataSize);
2279 }
2280 ZwClose(KeyHandle);
2281 }
2282 }
2283 RtlFreeUnicodeString(&LoadFont.RegValueName);
2284
2285 RtlFreeUnicodeString(&PathName);
2286 return FontCount;
2287 }
2288
2289 INT FASTCALL
IntGdiAddFontResource(PUNICODE_STRING FileName,DWORD Characteristics)2290 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
2291 {
2292 return IntGdiAddFontResourceEx(FileName, Characteristics, 0);
2293 }
2294
2295 /* Borrowed from shlwapi!PathIsRelativeW */
PathIsRelativeW(LPCWSTR lpszPath)2296 BOOL WINAPI PathIsRelativeW(LPCWSTR lpszPath)
2297 {
2298 if (!lpszPath || !*lpszPath)
2299 return TRUE;
2300 if (*lpszPath == L'\\' || (*lpszPath && lpszPath[1] == L':'))
2301 return FALSE;
2302 return TRUE;
2303 }
2304
2305 BOOL FASTCALL
IntLoadFontsInRegistry(VOID)2306 IntLoadFontsInRegistry(VOID)
2307 {
2308 NTSTATUS Status;
2309 HANDLE KeyHandle;
2310 OBJECT_ATTRIBUTES ObjectAttributes;
2311 KEY_FULL_INFORMATION KeyFullInfo;
2312 ULONG i, Length;
2313 UNICODE_STRING FontTitleW, FileNameW;
2314 SIZE_T InfoSize;
2315 LPBYTE InfoBuffer;
2316 PKEY_VALUE_FULL_INFORMATION pInfo;
2317 LPWSTR pchPath;
2318 WCHAR szPath[MAX_PATH];
2319 INT nFontCount = 0;
2320 DWORD dwFlags;
2321
2322 /* open registry key */
2323 InitializeObjectAttributes(&ObjectAttributes, &g_FontRegPath,
2324 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2325 NULL, NULL);
2326 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
2327 if (!NT_SUCCESS(Status))
2328 {
2329 DPRINT1("ZwOpenKey failed: 0x%08X\n", Status);
2330 return FALSE; /* failure */
2331 }
2332
2333 /* query count of values */
2334 Status = ZwQueryKey(KeyHandle, KeyFullInformation,
2335 &KeyFullInfo, sizeof(KeyFullInfo), &Length);
2336 if (!NT_SUCCESS(Status))
2337 {
2338 DPRINT1("ZwQueryKey failed: 0x%08X\n", Status);
2339 ZwClose(KeyHandle);
2340 return FALSE; /* failure */
2341 }
2342
2343 /* allocate buffer */
2344 InfoSize = (MAX_PATH + 256) * sizeof(WCHAR);
2345 InfoBuffer = ExAllocatePoolWithTag(PagedPool, InfoSize, TAG_FONT);
2346 if (!InfoBuffer)
2347 {
2348 DPRINT1("ExAllocatePoolWithTag failed\n");
2349 ZwClose(KeyHandle);
2350 return FALSE;
2351 }
2352
2353 /* for each value */
2354 for (i = 0; i < KeyFullInfo.Values; ++i)
2355 {
2356 /* get value name */
2357 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
2358 InfoBuffer, InfoSize, &Length);
2359 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2360 {
2361 /* too short buffer */
2362 ExFreePoolWithTag(InfoBuffer, TAG_FONT);
2363 InfoSize *= 2;
2364 InfoBuffer = ExAllocatePoolWithTag(PagedPool, InfoSize, TAG_FONT);
2365 if (!InfoBuffer)
2366 {
2367 DPRINT1("ExAllocatePoolWithTag failed\n");
2368 break;
2369 }
2370 /* try again */
2371 Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
2372 InfoBuffer, InfoSize, &Length);
2373 }
2374 if (!NT_SUCCESS(Status))
2375 {
2376 DPRINT1("ZwEnumerateValueKey failed: 0x%08X\n", Status);
2377 break; /* failure */
2378 }
2379
2380 /* create FontTitleW string */
2381 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
2382 Length = pInfo->NameLength / sizeof(WCHAR);
2383 pInfo->Name[Length] = UNICODE_NULL; /* truncate */
2384 if (!RtlCreateUnicodeString(&FontTitleW, pInfo->Name))
2385 {
2386 Status = STATUS_INSUFFICIENT_RESOURCES;
2387 DPRINT1("RtlCreateUnicodeString failed\n");
2388 break; /* failure */
2389 }
2390
2391 /* query value */
2392 Status = ZwQueryValueKey(KeyHandle, &FontTitleW, KeyValueFullInformation,
2393 InfoBuffer, InfoSize, &Length);
2394 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2395 {
2396 /* too short buffer */
2397 ExFreePoolWithTag(InfoBuffer, TAG_FONT);
2398 InfoSize *= 2;
2399 InfoBuffer = ExAllocatePoolWithTag(PagedPool, InfoSize, TAG_FONT);
2400 if (!InfoBuffer)
2401 {
2402 DPRINT1("ExAllocatePoolWithTag failed\n");
2403 break;
2404 }
2405 /* try again */
2406 Status = ZwQueryValueKey(KeyHandle, &FontTitleW, KeyValueFullInformation,
2407 InfoBuffer, InfoSize, &Length);
2408 }
2409 pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
2410 if (!NT_SUCCESS(Status) || !pInfo->DataLength)
2411 {
2412 DPRINT1("ZwQueryValueKey failed: 0x%08X\n", Status);
2413 RtlFreeUnicodeString(&FontTitleW);
2414 break; /* failure */
2415 }
2416
2417 /* Build pchPath */
2418 pchPath = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
2419 Length = pInfo->DataLength / sizeof(WCHAR);
2420 pchPath[Length] = UNICODE_NULL; /* truncate */
2421
2422 /* Load font(s) without writing registry */
2423 if (PathIsRelativeW(pchPath))
2424 {
2425 dwFlags = 0;
2426 Status = RtlStringCbPrintfW(szPath, sizeof(szPath),
2427 L"\\SystemRoot\\Fonts\\%s", pchPath);
2428 }
2429 else
2430 {
2431 dwFlags = AFRX_ALTERNATIVE_PATH | AFRX_DOS_DEVICE_PATH;
2432 Status = RtlStringCbCopyW(szPath, sizeof(szPath), pchPath);
2433 }
2434
2435 if (NT_SUCCESS(Status))
2436 {
2437 RtlCreateUnicodeString(&FileNameW, szPath);
2438 nFontCount += IntGdiAddFontResourceEx(&FileNameW, 0, dwFlags);
2439 RtlFreeUnicodeString(&FileNameW);
2440 }
2441
2442 RtlFreeUnicodeString(&FontTitleW);
2443 }
2444
2445 /* close now */
2446 ZwClose(KeyHandle);
2447
2448 /* free memory block */
2449 if (InfoBuffer)
2450 {
2451 ExFreePoolWithTag(InfoBuffer, TAG_FONT);
2452 }
2453
2454 return (KeyFullInfo.Values != 0 && nFontCount != 0);
2455 }
2456
2457 HANDLE FASTCALL
IntGdiAddFontMemResource(PVOID Buffer,DWORD dwSize,PDWORD pNumAdded)2458 IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
2459 {
2460 HANDLE Ret = NULL;
2461 GDI_LOAD_FONT LoadFont;
2462 PFONT_ENTRY_COLL_MEM EntryCollection;
2463 INT FaceCount;
2464
2465 PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
2466 if (!BufferCopy)
2467 {
2468 *pNumAdded = 0;
2469 return NULL;
2470 }
2471 RtlCopyMemory(BufferCopy, Buffer, dwSize);
2472
2473 LoadFont.pFileName = NULL;
2474 LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
2475 LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
2476 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
2477 LoadFont.IsTrueType = FALSE;
2478 LoadFont.PrivateEntry = NULL;
2479 FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
2480
2481 RtlFreeUnicodeString(&LoadFont.RegValueName);
2482
2483 /* Release our copy */
2484 IntLockFreeType();
2485 SharedMem_Release(LoadFont.Memory);
2486 IntUnLockFreeType();
2487
2488 if (FaceCount > 0)
2489 {
2490 EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
2491 if (EntryCollection)
2492 {
2493 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
2494 EntryCollection->Entry = LoadFont.PrivateEntry;
2495 IntLockFreeType();
2496 IntLockProcessPrivateFonts(Win32Process);
2497 EntryCollection->Handle = ULongToHandle(++Win32Process->PrivateMemFontHandleCount);
2498 InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
2499 IntUnLockProcessPrivateFonts(Win32Process);
2500 IntUnLockFreeType();
2501 Ret = EntryCollection->Handle;
2502 }
2503 }
2504 *pNumAdded = FaceCount;
2505
2506 return Ret;
2507 }
2508
2509 // FIXME: Add RemoveFontResource
2510
2511 VOID FASTCALL
IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)2512 IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
2513 {
2514 PLIST_ENTRY Entry;
2515 PFONT_ENTRY_MEM FontEntry;
2516
2517 while (!IsListEmpty(&Head->ListEntry))
2518 {
2519 Entry = RemoveHeadList(&Head->ListEntry);
2520 FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
2521
2522 CleanupFontEntry(FontEntry->Entry);
2523 ExFreePoolWithTag(FontEntry, TAG_FONT);
2524 }
2525
2526 CleanupFontEntry(Head->Entry);
2527 ExFreePoolWithTag(Head, TAG_FONT);
2528 }
2529
2530 static VOID FASTCALL
UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)2531 UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)
2532 {
2533 PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
2534 PLIST_ENTRY ListEntry;
2535 RemoveEntryList(&Collection->ListEntry);
2536
2537 do {
2538 /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
2539 RemoveEntryList(&FontMemEntry->Entry->ListEntry);
2540
2541 ListEntry = FontMemEntry->ListEntry.Flink;
2542 FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
2543
2544 } while (FontMemEntry != Collection->Entry);
2545 }
2546
2547 BOOL FASTCALL
IntGdiRemoveFontMemResource(HANDLE hMMFont)2548 IntGdiRemoveFontMemResource(HANDLE hMMFont)
2549 {
2550 PLIST_ENTRY Entry;
2551 PFONT_ENTRY_COLL_MEM CurrentEntry;
2552 PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
2553 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
2554
2555 IntLockFreeType();
2556 IntLockProcessPrivateFonts(Win32Process);
2557 for (Entry = Win32Process->PrivateMemFontListHead.Flink;
2558 Entry != &Win32Process->PrivateMemFontListHead;
2559 Entry = Entry->Flink)
2560 {
2561 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
2562
2563 if (CurrentEntry->Handle == hMMFont)
2564 {
2565 EntryCollection = CurrentEntry;
2566 UnlinkFontMemCollection(CurrentEntry);
2567 break;
2568 }
2569 }
2570 IntUnLockProcessPrivateFonts(Win32Process);
2571 IntUnLockFreeType();
2572
2573 if (EntryCollection)
2574 {
2575 IntGdiCleanupMemEntry(EntryCollection->Entry);
2576 ExFreePoolWithTag(EntryCollection, TAG_FONT);
2577 return TRUE;
2578 }
2579 return FALSE;
2580 }
2581
2582
2583 VOID FASTCALL
IntGdiCleanupPrivateFontsForProcess(VOID)2584 IntGdiCleanupPrivateFontsForProcess(VOID)
2585 {
2586 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
2587 PLIST_ENTRY Entry;
2588 PFONT_ENTRY_COLL_MEM EntryCollection;
2589
2590 DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
2591 do {
2592 Entry = NULL;
2593 EntryCollection = NULL;
2594
2595 IntLockFreeType();
2596 IntLockProcessPrivateFonts(Win32Process);
2597 if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
2598 {
2599 Entry = Win32Process->PrivateMemFontListHead.Flink;
2600 EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
2601 UnlinkFontMemCollection(EntryCollection);
2602 }
2603 IntUnLockProcessPrivateFonts(Win32Process);
2604 IntUnLockFreeType();
2605
2606 if (EntryCollection)
2607 {
2608 IntGdiCleanupMemEntry(EntryCollection->Entry);
2609 ExFreePoolWithTag(EntryCollection, TAG_FONT);
2610 }
2611 else
2612 {
2613 /* No Mem fonts anymore, see if we have any other private fonts left */
2614 Entry = NULL;
2615 IntLockFreeType();
2616 IntLockProcessPrivateFonts(Win32Process);
2617 if (!IsListEmpty(&Win32Process->PrivateFontListHead))
2618 {
2619 Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
2620 }
2621 IntUnLockProcessPrivateFonts(Win32Process);
2622 IntUnLockFreeType();
2623
2624 if (Entry)
2625 {
2626 CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
2627 }
2628 }
2629
2630 } while (Entry);
2631 }
2632
2633 BOOL FASTCALL
IntIsFontRenderingEnabled(VOID)2634 IntIsFontRenderingEnabled(VOID)
2635 {
2636 return (gpsi->BitsPixel > 8) && g_RenderingEnabled;
2637 }
2638
2639 VOID FASTCALL
IntEnableFontRendering(BOOL Enable)2640 IntEnableFontRendering(BOOL Enable)
2641 {
2642 g_RenderingEnabled = Enable;
2643 }
2644
2645 FT_Render_Mode FASTCALL
IntGetFontRenderMode(LOGFONTW * logfont)2646 IntGetFontRenderMode(LOGFONTW *logfont)
2647 {
2648 switch (logfont->lfQuality)
2649 {
2650 case ANTIALIASED_QUALITY:
2651 break;
2652 case NONANTIALIASED_QUALITY:
2653 return FT_RENDER_MODE_MONO;
2654 case DRAFT_QUALITY:
2655 return FT_RENDER_MODE_LIGHT;
2656 case CLEARTYPE_QUALITY:
2657 if (!gspv.bFontSmoothing)
2658 break;
2659 if (!gspv.uiFontSmoothingType)
2660 break;
2661 return FT_RENDER_MODE_LCD;
2662 }
2663 return FT_RENDER_MODE_NORMAL;
2664 }
2665
2666
2667 NTSTATUS FASTCALL
TextIntCreateFontIndirect(CONST LPLOGFONTW lf,HFONT * NewFont)2668 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
2669 {
2670 PLFONT plfont;
2671 LOGFONTW *plf;
2672
2673 ASSERT(lf);
2674 plfont = LFONT_AllocFontWithHandle();
2675 if (!plfont)
2676 {
2677 return STATUS_NO_MEMORY;
2678 }
2679
2680 ExInitializePushLock(&plfont->lock);
2681 *NewFont = plfont->BaseObject.hHmgr;
2682 plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
2683 RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
2684 if (lf->lfEscapement != lf->lfOrientation)
2685 {
2686 /* This should really depend on whether GM_ADVANCED is set */
2687 plf->lfOrientation = plf->lfEscapement;
2688 }
2689 LFONT_UnlockFont(plfont);
2690
2691 return STATUS_SUCCESS;
2692 }
2693
2694 /*************************************************************************
2695 * TranslateCharsetInfo
2696 *
2697 * Fills a CHARSETINFO structure for a character set, code page, or
2698 * font. This allows making the correspondance between different labelings
2699 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2700 * of the same encoding.
2701 *
2702 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
2703 * only one codepage should be set in *Src.
2704 *
2705 * RETURNS
2706 * TRUE on success, FALSE on failure.
2707 *
2708 */
2709 static BOOLEAN
IntTranslateCharsetInfo(PDWORD Src,LPCHARSETINFO Cs,DWORD Flags)2710 IntTranslateCharsetInfo(PDWORD Src, /* [in]
2711 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2712 if flags == TCI_SRCCHARSET: a character set value
2713 if flags == TCI_SRCCODEPAGE: a code page value */
2714 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
2715 DWORD Flags /* [in] determines interpretation of lpSrc */)
2716 {
2717 int Index = 0;
2718
2719 switch (Flags)
2720 {
2721 case TCI_SRCFONTSIG:
2722 while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
2723 {
2724 Index++;
2725 }
2726 break;
2727 case TCI_SRCCODEPAGE:
2728 while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciACP)
2729 {
2730 Index++;
2731 }
2732 break;
2733 case TCI_SRCCHARSET:
2734 while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciCharset)
2735 {
2736 Index++;
2737 }
2738 break;
2739 case TCI_SRCLOCALE:
2740 UNIMPLEMENTED;
2741 return FALSE;
2742 default:
2743 return FALSE;
2744 }
2745
2746 if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == g_FontTci[Index].ciCharset)
2747 {
2748 return FALSE;
2749 }
2750
2751 RtlCopyMemory(Cs, &g_FontTci[Index], sizeof(CHARSETINFO));
2752
2753 return TRUE;
2754 }
2755
2756
face_has_symbol_charmap(FT_Face ft_face)2757 static BOOL face_has_symbol_charmap(FT_Face ft_face)
2758 {
2759 int i;
2760
2761 for(i = 0; i < ft_face->num_charmaps; i++)
2762 {
2763 if (ft_face->charmaps[i]->platform_id == TT_PLATFORM_MICROSOFT &&
2764 ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
2765 {
2766 return TRUE;
2767 }
2768 }
2769 return FALSE;
2770 }
2771
2772 static void FASTCALL
FillTM(TEXTMETRICW * TM,PFONTGDI FontGDI,TT_OS2 * pOS2,TT_HoriHeader * pHori,FT_WinFNT_HeaderRec * pFNT)2773 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
2774 TT_OS2 *pOS2, TT_HoriHeader *pHori,
2775 FT_WinFNT_HeaderRec *pFNT)
2776 {
2777 FT_Fixed XScale, YScale;
2778 int Ascent, Descent;
2779 FT_Face Face = FontGDI->SharedFace->Face;
2780
2781 ASSERT_FREETYPE_LOCK_HELD();
2782
2783 XScale = Face->size->metrics.x_scale;
2784 YScale = Face->size->metrics.y_scale;
2785
2786 if (pFNT)
2787 {
2788 TM->tmHeight = pFNT->pixel_height;
2789 TM->tmAscent = pFNT->ascent;
2790 TM->tmDescent = TM->tmHeight - TM->tmAscent;
2791 TM->tmInternalLeading = pFNT->internal_leading;
2792 TM->tmExternalLeading = pFNT->external_leading;
2793 TM->tmAveCharWidth = pFNT->avg_width;
2794 TM->tmMaxCharWidth = pFNT->max_width;
2795 TM->tmOverhang = 0;
2796 TM->tmDigitizedAspectX = pFNT->horizontal_resolution;
2797 TM->tmDigitizedAspectY = pFNT->vertical_resolution;
2798 TM->tmFirstChar = pFNT->first_char;
2799 TM->tmLastChar = pFNT->last_char;
2800 TM->tmDefaultChar = pFNT->default_char + pFNT->first_char;
2801 TM->tmBreakChar = pFNT->break_char + pFNT->first_char;
2802 TM->tmPitchAndFamily = pFNT->pitch_and_family;
2803 TM->tmWeight = FontGDI->RequestWeight;
2804 TM->tmItalic = FontGDI->RequestItalic;
2805 TM->tmUnderlined = FontGDI->RequestUnderline;
2806 TM->tmStruckOut = FontGDI->RequestStrikeOut;
2807 TM->tmCharSet = FontGDI->CharSet;
2808 return;
2809 }
2810
2811 ASSERT(pOS2);
2812 if (!pOS2)
2813 return;
2814
2815 if ((FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent == 0)
2816 {
2817 Ascent = pHori->Ascender;
2818 Descent = -pHori->Descender;
2819 }
2820 else
2821 {
2822 Ascent = (FT_Short)pOS2->usWinAscent;
2823 Descent = (FT_Short)pOS2->usWinDescent;
2824 }
2825
2826 TM->tmAscent = FontGDI->tmAscent;
2827 TM->tmDescent = FontGDI->tmDescent;
2828 TM->tmHeight = TM->tmAscent + TM->tmDescent;
2829 TM->tmInternalLeading = FontGDI->tmInternalLeading;
2830
2831 /* MSDN says:
2832 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2833 */
2834 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
2835 - ((Ascent + Descent)
2836 - (pHori->Ascender - pHori->Descender)),
2837 YScale) + 32) >> 6);
2838 if (FontGDI->lfWidth != 0)
2839 TM->tmAveCharWidth = FontGDI->lfWidth;
2840 else
2841 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
2842
2843 if (TM->tmAveCharWidth == 0)
2844 TM->tmAveCharWidth = 1;
2845
2846 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
2847 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
2848
2849 if (FontGDI->OriginalWeight != FW_DONTCARE &&
2850 FontGDI->OriginalWeight != FW_NORMAL)
2851 {
2852 TM->tmWeight = FontGDI->OriginalWeight;
2853 }
2854 else
2855 {
2856 TM->tmWeight = FontGDI->RequestWeight;
2857 }
2858
2859 TM->tmOverhang = 0;
2860 TM->tmDigitizedAspectX = 96;
2861 TM->tmDigitizedAspectY = 96;
2862 if (face_has_symbol_charmap(Face) ||
2863 (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
2864 {
2865 USHORT cpOEM, cpAnsi;
2866
2867 EngGetCurrentCodePage(&cpOEM, &cpAnsi);
2868 TM->tmFirstChar = 0;
2869 switch(cpAnsi)
2870 {
2871 case 1257: /* Baltic */
2872 TM->tmLastChar = 0xf8fd;
2873 break;
2874 default:
2875 TM->tmLastChar = 0xf0ff;
2876 }
2877 TM->tmBreakChar = 0x20;
2878 TM->tmDefaultChar = 0x1f;
2879 }
2880 else
2881 {
2882 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
2883 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
2884
2885 if(pOS2->usFirstCharIndex <= 1)
2886 TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
2887 else if (pOS2->usFirstCharIndex > 0xff)
2888 TM->tmBreakChar = 0x20;
2889 else
2890 TM->tmBreakChar = pOS2->usFirstCharIndex;
2891 TM->tmDefaultChar = TM->tmBreakChar - 1;
2892 }
2893
2894 if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
2895 {
2896 TM->tmItalic = 0xFF;
2897 }
2898 else
2899 {
2900 TM->tmItalic = 0;
2901 }
2902 TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
2903 TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
2904
2905 if (!FT_IS_FIXED_WIDTH(Face))
2906 {
2907 switch (pOS2->panose[PAN_PROPORTION_INDEX])
2908 {
2909 case PAN_PROP_MONOSPACED:
2910 TM->tmPitchAndFamily = 0;
2911 break;
2912 default:
2913 TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH;
2914 break;
2915 }
2916 }
2917 else
2918 {
2919 TM->tmPitchAndFamily = 0;
2920 }
2921
2922 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
2923 {
2924 case PAN_FAMILY_SCRIPT:
2925 TM->tmPitchAndFamily |= FF_SCRIPT;
2926 break;
2927 case PAN_FAMILY_DECORATIVE:
2928 TM->tmPitchAndFamily |= FF_DECORATIVE;
2929 break;
2930
2931 case PAN_ANY:
2932 case PAN_NO_FIT:
2933 case PAN_FAMILY_TEXT_DISPLAY:
2934 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
2935 /* Which is clearly not what the panose spec says. */
2936 if (TM->tmPitchAndFamily == 0) /* Fixed */
2937 {
2938 TM->tmPitchAndFamily = FF_MODERN;
2939 }
2940 else
2941 {
2942 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
2943 {
2944 case PAN_ANY:
2945 case PAN_NO_FIT:
2946 default:
2947 TM->tmPitchAndFamily |= FF_DONTCARE;
2948 break;
2949
2950 case PAN_SERIF_COVE:
2951 case PAN_SERIF_OBTUSE_COVE:
2952 case PAN_SERIF_SQUARE_COVE:
2953 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2954 case PAN_SERIF_SQUARE:
2955 case PAN_SERIF_THIN:
2956 case PAN_SERIF_BONE:
2957 case PAN_SERIF_EXAGGERATED:
2958 case PAN_SERIF_TRIANGLE:
2959 TM->tmPitchAndFamily |= FF_ROMAN;
2960 break;
2961
2962 case PAN_SERIF_NORMAL_SANS:
2963 case PAN_SERIF_OBTUSE_SANS:
2964 case PAN_SERIF_PERP_SANS:
2965 case PAN_SERIF_FLARED:
2966 case PAN_SERIF_ROUNDED:
2967 TM->tmPitchAndFamily |= FF_SWISS;
2968 break;
2969 }
2970 }
2971 break;
2972 default:
2973 TM->tmPitchAndFamily |= FF_DONTCARE;
2974 }
2975
2976 if (FT_IS_SCALABLE(Face))
2977 {
2978 TM->tmPitchAndFamily |= TMPF_VECTOR;
2979 }
2980 if (FT_IS_SFNT(Face))
2981 {
2982 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
2983 }
2984
2985 TM->tmCharSet = FontGDI->CharSet;
2986 }
2987
2988 static NTSTATUS
2989 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
2990 FT_UShort NameID, FT_UShort LangID);
2991
2992 typedef struct FONT_NAMES
2993 {
2994 UNICODE_STRING FamilyNameW; /* family name (TT_NAME_ID_FONT_FAMILY) */
2995 UNICODE_STRING FaceNameW; /* face name (TT_NAME_ID_FULL_NAME) */
2996 UNICODE_STRING StyleNameW; /* style name (TT_NAME_ID_FONT_SUBFAMILY) */
2997 UNICODE_STRING FullNameW; /* unique name (TT_NAME_ID_UNIQUE_ID) */
2998 ULONG OtmSize; /* size of OUTLINETEXTMETRICW with extra data */
2999 } FONT_NAMES, *LPFONT_NAMES;
3000
3001 static __inline void FASTCALL
IntInitFontNames(FONT_NAMES * Names,PSHARED_FACE SharedFace)3002 IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace)
3003 {
3004 ULONG OtmSize;
3005
3006 RtlInitUnicodeString(&Names->FamilyNameW, NULL);
3007 RtlInitUnicodeString(&Names->FaceNameW, NULL);
3008 RtlInitUnicodeString(&Names->StyleNameW, NULL);
3009 RtlInitUnicodeString(&Names->FullNameW, NULL);
3010
3011 /* family name */
3012 IntGetFontLocalizedName(&Names->FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
3013 /* face name */
3014 IntGetFontLocalizedName(&Names->FaceNameW, SharedFace, TT_NAME_ID_FULL_NAME, gusLanguageID);
3015 /* style name */
3016 IntGetFontLocalizedName(&Names->StyleNameW, SharedFace, TT_NAME_ID_FONT_SUBFAMILY, gusLanguageID);
3017 /* unique name (full name) */
3018 IntGetFontLocalizedName(&Names->FullNameW, SharedFace, TT_NAME_ID_UNIQUE_ID, gusLanguageID);
3019
3020 /* Calculate the size of OUTLINETEXTMETRICW with extra data */
3021 OtmSize = sizeof(OUTLINETEXTMETRICW) +
3022 Names->FamilyNameW.Length + sizeof(UNICODE_NULL) +
3023 Names->FaceNameW.Length + sizeof(UNICODE_NULL) +
3024 Names->StyleNameW.Length + sizeof(UNICODE_NULL) +
3025 Names->FullNameW.Length + sizeof(UNICODE_NULL);
3026 Names->OtmSize = OtmSize;
3027 }
3028
3029 static __inline SIZE_T FASTCALL
IntStoreName(const UNICODE_STRING * pName,BYTE * pb)3030 IntStoreName(const UNICODE_STRING *pName, BYTE *pb)
3031 {
3032 RtlCopyMemory(pb, pName->Buffer, pName->Length);
3033 *(WCHAR *)&pb[pName->Length] = UNICODE_NULL;
3034 return pName->Length + sizeof(UNICODE_NULL);
3035 }
3036
3037 static __inline BYTE *FASTCALL
IntStoreFontNames(const FONT_NAMES * Names,OUTLINETEXTMETRICW * Otm)3038 IntStoreFontNames(const FONT_NAMES *Names, OUTLINETEXTMETRICW *Otm)
3039 {
3040 BYTE *pb = (BYTE *)Otm + sizeof(OUTLINETEXTMETRICW);
3041
3042 /* family name */
3043 Otm->otmpFamilyName = (LPSTR)(pb - (BYTE*) Otm);
3044 pb += IntStoreName(&Names->FamilyNameW, pb);
3045
3046 /* face name */
3047 Otm->otmpFaceName = (LPSTR)(pb - (BYTE*) Otm);
3048 pb += IntStoreName(&Names->FaceNameW, pb);
3049
3050 /* style name */
3051 Otm->otmpStyleName = (LPSTR)(pb - (BYTE*) Otm);
3052 pb += IntStoreName(&Names->StyleNameW, pb);
3053
3054 /* unique name (full name) */
3055 Otm->otmpFullName = (LPSTR)(pb - (BYTE*) Otm);
3056 pb += IntStoreName(&Names->FullNameW, pb);
3057
3058 return pb;
3059 }
3060
3061 static __inline void FASTCALL
IntFreeFontNames(FONT_NAMES * Names)3062 IntFreeFontNames(FONT_NAMES *Names)
3063 {
3064 RtlFreeUnicodeString(&Names->FamilyNameW);
3065 RtlFreeUnicodeString(&Names->FaceNameW);
3066 RtlFreeUnicodeString(&Names->StyleNameW);
3067 RtlFreeUnicodeString(&Names->FullNameW);
3068 }
3069
3070 /*************************************************************
3071 * IntGetOutlineTextMetrics
3072 *
3073 */
3074 INT FASTCALL
IntGetOutlineTextMetrics(PFONTGDI FontGDI,UINT Size,OUTLINETEXTMETRICW * Otm,BOOL bLocked)3075 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
3076 UINT Size,
3077 OUTLINETEXTMETRICW *Otm,
3078 BOOL bLocked)
3079 {
3080 TT_OS2 *pOS2;
3081 TT_HoriHeader *pHori;
3082 TT_Postscript *pPost;
3083 FT_Fixed XScale, YScale;
3084 FT_WinFNT_HeaderRec WinFNT;
3085 FT_Error Error;
3086 BYTE *pb;
3087 FONT_NAMES FontNames;
3088 PSHARED_FACE SharedFace = FontGDI->SharedFace;
3089 PSHARED_FACE_CACHE Cache;
3090 FT_Face Face = SharedFace->Face;
3091
3092 if (bLocked)
3093 ASSERT_FREETYPE_LOCK_HELD();
3094 else
3095 ASSERT_FREETYPE_LOCK_NOT_HELD();
3096
3097 if (PRIMARYLANGID(gusLanguageID) == LANG_ENGLISH)
3098 {
3099 Cache = &SharedFace->EnglishUS;
3100 }
3101 else
3102 {
3103 Cache = &SharedFace->UserLanguage;
3104 }
3105
3106 if (Size == 0 && Cache->OutlineRequiredSize > 0)
3107 {
3108 ASSERT(Otm == NULL);
3109 return Cache->OutlineRequiredSize;
3110 }
3111
3112 if (!bLocked)
3113 IntLockFreeType();
3114
3115 IntInitFontNames(&FontNames, SharedFace);
3116 Cache->OutlineRequiredSize = FontNames.OtmSize;
3117
3118 if (Size == 0)
3119 {
3120 ASSERT(Otm == NULL);
3121 IntFreeFontNames(&FontNames);
3122 if (!bLocked)
3123 IntUnLockFreeType();
3124 return Cache->OutlineRequiredSize;
3125 }
3126
3127 ASSERT(Otm != NULL);
3128
3129 if (Size < Cache->OutlineRequiredSize)
3130 {
3131 DPRINT1("Size %u < OutlineRequiredSize %u\n", Size,
3132 Cache->OutlineRequiredSize);
3133 IntFreeFontNames(&FontNames);
3134 if (!bLocked)
3135 IntUnLockFreeType();
3136 return 0; /* failure */
3137 }
3138
3139 XScale = Face->size->metrics.x_scale;
3140 YScale = Face->size->metrics.y_scale;
3141
3142 pOS2 = FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
3143 pHori = FT_Get_Sfnt_Table(Face, FT_SFNT_HHEA);
3144 pPost = FT_Get_Sfnt_Table(Face, FT_SFNT_POST); /* We can live with this failing */
3145 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
3146
3147 if (pOS2 == NULL && Error)
3148 {
3149 if (!bLocked)
3150 IntUnLockFreeType();
3151 DPRINT1("Can't find OS/2 table - not TT font?\n");
3152 IntFreeFontNames(&FontNames);
3153 return 0;
3154 }
3155
3156 if (pHori == NULL && Error)
3157 {
3158 if (!bLocked)
3159 IntUnLockFreeType();
3160 DPRINT1("Can't find HHEA table - not TT font?\n");
3161 IntFreeFontNames(&FontNames);
3162 return 0;
3163 }
3164
3165 Otm->otmSize = Cache->OutlineRequiredSize;
3166
3167 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &WinFNT : 0);
3168
3169 if (!pOS2)
3170 goto skip_os2;
3171
3172 Otm->otmFiller = 0;
3173 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3174 Otm->otmfsSelection = pOS2->fsSelection;
3175 Otm->otmfsType = pOS2->fsType;
3176 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3177 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3178 Otm->otmItalicAngle = 0; /* POST table */
3179 Otm->otmEMSquare = Face->units_per_EM;
3180
3181 #define SCALE_X(value) ((FT_MulFix((value), XScale) + 32) >> 6)
3182 #define SCALE_Y(value) ((FT_MulFix((value), YScale) + 32) >> 6)
3183
3184 Otm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
3185 Otm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
3186 Otm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
3187 Otm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
3188 Otm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
3189 Otm->otmrcFontBox.left = SCALE_X(Face->bbox.xMin);
3190 Otm->otmrcFontBox.right = SCALE_X(Face->bbox.xMax);
3191 Otm->otmrcFontBox.top = SCALE_Y(Face->bbox.yMax);
3192 Otm->otmrcFontBox.bottom = SCALE_Y(Face->bbox.yMin);
3193 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
3194 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
3195 Otm->otmMacLineGap = Otm->otmLineGap;
3196 Otm->otmusMinimumPPEM = 0; /* TT Header */
3197 Otm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
3198 Otm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
3199 Otm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
3200 Otm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
3201 Otm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
3202 Otm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
3203 Otm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
3204 Otm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
3205 Otm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
3206 Otm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
3207
3208 if (!pPost)
3209 {
3210 Otm->otmsUnderscoreSize = 0;
3211 Otm->otmsUnderscorePosition = 0;
3212 }
3213 else
3214 {
3215 Otm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
3216 Otm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
3217 }
3218
3219 #undef SCALE_X
3220 #undef SCALE_Y
3221
3222 skip_os2:
3223 if (!bLocked)
3224 IntUnLockFreeType();
3225
3226 pb = IntStoreFontNames(&FontNames, Otm);
3227 ASSERT(pb - (BYTE*)Otm == Cache->OutlineRequiredSize);
3228
3229 IntFreeFontNames(&FontNames);
3230
3231 return Cache->OutlineRequiredSize;
3232 }
3233
3234 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
3235 static BYTE
CharSetFromLangID(LANGID LangID)3236 CharSetFromLangID(LANGID LangID)
3237 {
3238 /* FIXME: Add more and fix if wrong */
3239 switch (PRIMARYLANGID(LangID))
3240 {
3241 case LANG_CHINESE:
3242 switch (SUBLANGID(LangID))
3243 {
3244 case SUBLANG_CHINESE_TRADITIONAL:
3245 return CHINESEBIG5_CHARSET;
3246 case SUBLANG_CHINESE_SIMPLIFIED:
3247 default:
3248 break;
3249 }
3250 return GB2312_CHARSET;
3251
3252 case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
3253 case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
3254 return EASTEUROPE_CHARSET;
3255
3256 case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
3257 case LANG_SERBIAN: case LANG_UKRAINIAN:
3258 return RUSSIAN_CHARSET;
3259
3260 case LANG_ARABIC: return ARABIC_CHARSET;
3261 case LANG_GREEK: return GREEK_CHARSET;
3262 case LANG_HEBREW: return HEBREW_CHARSET;
3263 case LANG_JAPANESE: return SHIFTJIS_CHARSET;
3264 case LANG_KOREAN: return JOHAB_CHARSET;
3265 case LANG_TURKISH: return TURKISH_CHARSET;
3266 case LANG_THAI: return THAI_CHARSET;
3267 case LANG_LATVIAN: return BALTIC_CHARSET;
3268 case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
3269
3270 case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
3271 case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
3272 case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
3273 case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
3274 case LANG_SWEDISH: default:
3275 return ANSI_CHARSET;
3276 }
3277 }
3278
3279 static void
SwapEndian(LPVOID pvData,DWORD Size)3280 SwapEndian(LPVOID pvData, DWORD Size)
3281 {
3282 BYTE b, *pb = pvData;
3283 Size /= 2;
3284 while (Size-- > 0)
3285 {
3286 b = pb[0];
3287 pb[0] = pb[1];
3288 pb[1] = b;
3289 ++pb; ++pb;
3290 }
3291 }
3292
3293 static NTSTATUS
IntGetFontLocalizedName(PUNICODE_STRING pNameW,PSHARED_FACE SharedFace,FT_UShort NameID,FT_UShort LangID)3294 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
3295 FT_UShort NameID, FT_UShort LangID)
3296 {
3297 FT_SfntName Name;
3298 INT i, Count, BestIndex, Score, BestScore;
3299 FT_Error Error;
3300 NTSTATUS Status = STATUS_NOT_FOUND;
3301 ANSI_STRING AnsiName;
3302 PSHARED_FACE_CACHE Cache;
3303 FT_Face Face = SharedFace->Face;
3304
3305 RtlFreeUnicodeString(pNameW);
3306
3307 /* select cache */
3308 if (PRIMARYLANGID(LangID) == LANG_ENGLISH)
3309 {
3310 Cache = &SharedFace->EnglishUS;
3311 }
3312 else
3313 {
3314 Cache = &SharedFace->UserLanguage;
3315 }
3316
3317 /* use cache if available */
3318 if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer)
3319 {
3320 return DuplicateUnicodeString(&Cache->FontFamily, pNameW);
3321 }
3322 if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer)
3323 {
3324 return DuplicateUnicodeString(&Cache->FullName, pNameW);
3325 }
3326
3327 BestIndex = -1;
3328 BestScore = 0;
3329
3330 Count = FT_Get_Sfnt_Name_Count(Face);
3331 for (i = 0; i < Count; ++i)
3332 {
3333 Error = FT_Get_Sfnt_Name(Face, i, &Name);
3334 if (Error)
3335 {
3336 continue; /* failure */
3337 }
3338
3339 if (Name.name_id != NameID)
3340 {
3341 continue; /* mismatched */
3342 }
3343
3344 if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
3345 (Name.encoding_id != TT_MS_ID_UNICODE_CS &&
3346 Name.encoding_id != TT_MS_ID_SYMBOL_CS))
3347 {
3348 continue; /* not Microsoft Unicode name */
3349 }
3350
3351 if (Name.string == NULL || Name.string_len == 0 ||
3352 (Name.string[0] == 0 && Name.string[1] == 0))
3353 {
3354 continue; /* invalid string */
3355 }
3356
3357 if (Name.language_id == LangID)
3358 {
3359 Score = 30;
3360 BestIndex = i;
3361 break; /* best match */
3362 }
3363 else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID))
3364 {
3365 Score = 20;
3366 }
3367 else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH)
3368 {
3369 Score = 10;
3370 }
3371 else
3372 {
3373 Score = 0;
3374 }
3375
3376 if (Score > BestScore)
3377 {
3378 BestScore = Score;
3379 BestIndex = i;
3380 }
3381 }
3382
3383 if (BestIndex >= 0)
3384 {
3385 /* store the best name */
3386 Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
3387 if (!Error)
3388 {
3389 /* NOTE: Name.string is not null-terminated */
3390 UNICODE_STRING Tmp;
3391 Tmp.Buffer = (PWCH)Name.string;
3392 Tmp.Length = Tmp.MaximumLength = Name.string_len;
3393
3394 pNameW->Length = 0;
3395 pNameW->MaximumLength = Name.string_len + sizeof(WCHAR);
3396 pNameW->Buffer = ExAllocatePoolWithTag(PagedPool, pNameW->MaximumLength, TAG_USTR);
3397
3398 if (pNameW->Buffer)
3399 {
3400 Status = RtlAppendUnicodeStringToString(pNameW, &Tmp);
3401 if (Status == STATUS_SUCCESS)
3402 {
3403 /* Convert UTF-16 big endian to little endian */
3404 SwapEndian(pNameW->Buffer, pNameW->Length);
3405 }
3406 }
3407 else
3408 {
3409 Status = STATUS_INSUFFICIENT_RESOURCES;
3410 }
3411 }
3412 }
3413
3414 if (!NT_SUCCESS(Status))
3415 {
3416 /* defaulted */
3417 if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
3418 {
3419 RtlInitAnsiString(&AnsiName, Face->style_name);
3420 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
3421 }
3422 else
3423 {
3424 RtlInitAnsiString(&AnsiName, Face->family_name);
3425 Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
3426 }
3427 }
3428
3429 if (NT_SUCCESS(Status))
3430 {
3431 /* make cache */
3432 if (NameID == TT_NAME_ID_FONT_FAMILY)
3433 {
3434 ASSERT_FREETYPE_LOCK_HELD();
3435 if (!Cache->FontFamily.Buffer)
3436 DuplicateUnicodeString(pNameW, &Cache->FontFamily);
3437 }
3438 else if (NameID == TT_NAME_ID_FULL_NAME)
3439 {
3440 ASSERT_FREETYPE_LOCK_HELD();
3441 if (!Cache->FullName.Buffer)
3442 DuplicateUnicodeString(pNameW, &Cache->FullName);
3443 }
3444 }
3445
3446 return Status;
3447 }
3448
3449 static void FASTCALL
FontFamilyFillInfo(PFONTFAMILYINFO Info,LPCWSTR FaceName,LPCWSTR FullName,PFONTGDI FontGDI)3450 FontFamilyFillInfo(PFONTFAMILYINFO Info, LPCWSTR FaceName,
3451 LPCWSTR FullName, PFONTGDI FontGDI)
3452 {
3453 ANSI_STRING StyleA;
3454 UNICODE_STRING StyleW;
3455 TT_OS2 *pOS2;
3456 FONTSIGNATURE fs;
3457 CHARSETINFO CharSetInfo;
3458 unsigned i, Size;
3459 OUTLINETEXTMETRICW *Otm;
3460 LOGFONTW *Lf;
3461 TEXTMETRICW *TM;
3462 NEWTEXTMETRICW *Ntm;
3463 DWORD fs0;
3464 NTSTATUS status;
3465 PSHARED_FACE SharedFace = FontGDI->SharedFace;
3466 FT_Face Face = SharedFace->Face;
3467 UNICODE_STRING NameW;
3468
3469 RtlInitUnicodeString(&NameW, NULL);
3470 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
3471 ASSERT_FREETYPE_LOCK_HELD();
3472 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL, TRUE);
3473 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3474 if (!Otm)
3475 {
3476 return;
3477 }
3478 ASSERT_FREETYPE_LOCK_HELD();
3479 Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm, TRUE);
3480 if (!Size)
3481 {
3482 ExFreePoolWithTag(Otm, GDITAG_TEXT);
3483 return;
3484 }
3485
3486 Lf = &Info->EnumLogFontEx.elfLogFont;
3487 TM = &Otm->otmTextMetrics;
3488
3489 Lf->lfHeight = TM->tmHeight;
3490 Lf->lfWidth = TM->tmAveCharWidth;
3491 Lf->lfWeight = TM->tmWeight;
3492 Lf->lfItalic = TM->tmItalic;
3493 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
3494 Lf->lfCharSet = TM->tmCharSet;
3495 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
3496 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
3497 Lf->lfQuality = PROOF_QUALITY;
3498
3499 Ntm = &Info->NewTextMetricEx.ntmTm;
3500 Ntm->tmHeight = TM->tmHeight;
3501 Ntm->tmAscent = TM->tmAscent;
3502 Ntm->tmDescent = TM->tmDescent;
3503 Ntm->tmInternalLeading = TM->tmInternalLeading;
3504 Ntm->tmExternalLeading = TM->tmExternalLeading;
3505 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
3506 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
3507 Ntm->tmWeight = TM->tmWeight;
3508 Ntm->tmOverhang = TM->tmOverhang;
3509 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
3510 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
3511 Ntm->tmFirstChar = TM->tmFirstChar;
3512 Ntm->tmLastChar = TM->tmLastChar;
3513 Ntm->tmDefaultChar = TM->tmDefaultChar;
3514 Ntm->tmBreakChar = TM->tmBreakChar;
3515 Ntm->tmItalic = TM->tmItalic;
3516 Ntm->tmUnderlined = TM->tmUnderlined;
3517 Ntm->tmStruckOut = TM->tmStruckOut;
3518 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
3519 Ntm->tmCharSet = TM->tmCharSet;
3520 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
3521
3522 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
3523
3524 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
3525
3526 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
3527 ? TRUETYPE_FONTTYPE : 0);
3528
3529 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
3530 Info->FontType |= RASTER_FONTTYPE;
3531
3532
3533 /* face name */
3534 if (!FaceName)
3535 FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
3536
3537 RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
3538
3539 /* full name */
3540 if (!FullName)
3541 FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName);
3542
3543 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
3544 sizeof(Info->EnumLogFontEx.elfFullName),
3545 FullName);
3546
3547 RtlInitAnsiString(&StyleA, Face->style_name);
3548 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
3549 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
3550 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
3551 if (!NT_SUCCESS(status))
3552 {
3553 ExFreePoolWithTag(Otm, GDITAG_TEXT);
3554 return;
3555 }
3556 Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
3557
3558 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3559
3560 if (!pOS2)
3561 {
3562 ExFreePoolWithTag(Otm, GDITAG_TEXT);
3563 return;
3564 }
3565
3566 Ntm->ntmSizeEM = Otm->otmEMSquare;
3567 Ntm->ntmCellHeight = (FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent;
3568 Ntm->ntmAvgWidth = 0;
3569
3570 ExFreePoolWithTag(Otm, GDITAG_TEXT);
3571
3572 fs.fsCsb[0] = pOS2->ulCodePageRange1;
3573 fs.fsCsb[1] = pOS2->ulCodePageRange2;
3574 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3575 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3576 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3577 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3578
3579 if (0 == pOS2->version)
3580 {
3581 FT_UInt Dummy;
3582
3583 if (FT_Get_First_Char(Face, &Dummy) < 0x100)
3584 fs.fsCsb[0] |= FS_LATIN1;
3585 else
3586 fs.fsCsb[0] |= FS_SYMBOL;
3587 }
3588
3589 if (fs.fsCsb[0] == 0)
3590 {
3591 /* Let's see if we can find any interesting cmaps */
3592 for (i = 0; i < (UINT)Face->num_charmaps; i++)
3593 {
3594 switch (Face->charmaps[i]->encoding)
3595 {
3596 case FT_ENCODING_UNICODE:
3597 case FT_ENCODING_APPLE_ROMAN:
3598 fs.fsCsb[0] |= FS_LATIN1;
3599 break;
3600 case FT_ENCODING_MS_SYMBOL:
3601 fs.fsCsb[0] |= FS_SYMBOL;
3602 break;
3603 default:
3604 break;
3605 }
3606 }
3607 }
3608
3609 for (i = 0; i < MAXTCIINDEX; i++)
3610 {
3611 fs0 = 1L << i;
3612 if (fs.fsCsb[0] & fs0)
3613 {
3614 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
3615 {
3616 CharSetInfo.ciCharset = DEFAULT_CHARSET;
3617 }
3618 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
3619 {
3620 if (g_ElfScripts[i])
3621 wcscpy(Info->EnumLogFontEx.elfScript, g_ElfScripts[i]);
3622 else
3623 {
3624 DPRINT1("Unknown elfscript for bit %u\n", i);
3625 }
3626 }
3627 }
3628 }
3629 Info->NewTextMetricEx.ntmFontSig = fs;
3630 }
3631
3632 static BOOLEAN FASTCALL
GetFontFamilyInfoForList(const LOGFONTW * LogFont,PFONTFAMILYINFO Info,LPCWSTR NominalName,LONG * pCount,LONG MaxCount,PLIST_ENTRY Head)3633 GetFontFamilyInfoForList(const LOGFONTW *LogFont,
3634 PFONTFAMILYINFO Info,
3635 LPCWSTR NominalName,
3636 LONG *pCount,
3637 LONG MaxCount,
3638 PLIST_ENTRY Head)
3639 {
3640 PLIST_ENTRY Entry;
3641 PFONT_ENTRY CurrentEntry;
3642 FONTGDI *FontGDI;
3643 FONTFAMILYINFO InfoEntry;
3644 LONG Count = *pCount;
3645
3646 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
3647 {
3648 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
3649 FontGDI = CurrentEntry->Font;
3650 ASSERT(FontGDI);
3651
3652 if (LogFont->lfCharSet != DEFAULT_CHARSET &&
3653 LogFont->lfCharSet != FontGDI->CharSet)
3654 {
3655 continue; /* charset mismatch */
3656 }
3657
3658 /* get one info entry */
3659 FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
3660
3661 if (LogFont->lfFaceName[0] != UNICODE_NULL)
3662 {
3663 /* check name */
3664 if (_wcsnicmp(LogFont->lfFaceName,
3665 InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
3666 RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0 &&
3667 _wcsnicmp(LogFont->lfFaceName,
3668 InfoEntry.EnumLogFontEx.elfFullName,
3669 RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0)
3670 {
3671 continue;
3672 }
3673 }
3674
3675 if (NominalName)
3676 {
3677 /* store the nominal name */
3678 RtlStringCbCopyW(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
3679 sizeof(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName),
3680 NominalName);
3681 }
3682
3683 /* store one entry to Info */
3684 if (0 <= Count && Count < MaxCount)
3685 {
3686 RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
3687 }
3688 Count++;
3689 }
3690
3691 *pCount = Count;
3692
3693 return TRUE;
3694 }
3695
3696 static BOOLEAN FASTCALL
GetFontFamilyInfoForSubstitutes(const LOGFONTW * LogFont,PFONTFAMILYINFO Info,LONG * pCount,LONG MaxCount)3697 GetFontFamilyInfoForSubstitutes(const LOGFONTW *LogFont,
3698 PFONTFAMILYINFO Info,
3699 LONG *pCount,
3700 LONG MaxCount)
3701 {
3702 PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead;
3703 PFONTSUBST_ENTRY pCurrentEntry;
3704 PUNICODE_STRING pFromW, pToW;
3705 LOGFONTW lf = *LogFont;
3706 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
3707
3708 for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
3709 {
3710 pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
3711
3712 pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
3713 if (LogFont->lfFaceName[0] != UNICODE_NULL)
3714 {
3715 /* check name */
3716 if (_wcsicmp(LogFont->lfFaceName, pFromW->Buffer) != 0)
3717 continue; /* mismatch */
3718 }
3719
3720 pToW = &pCurrentEntry->FontNames[FONTSUBST_TO];
3721 if (RtlEqualUnicodeString(pFromW, pToW, TRUE) &&
3722 pCurrentEntry->CharSets[FONTSUBST_FROM] ==
3723 pCurrentEntry->CharSets[FONTSUBST_TO])
3724 {
3725 /* identical mapping */
3726 continue;
3727 }
3728
3729 /* substitute and get the real name */
3730 IntUnicodeStringToBuffer(lf.lfFaceName, sizeof(lf.lfFaceName), pFromW);
3731 SubstituteFontRecurse(&lf);
3732 if (LogFont->lfCharSet != DEFAULT_CHARSET && LogFont->lfCharSet != lf.lfCharSet)
3733 continue;
3734
3735 /* search in global fonts */
3736 IntLockFreeType();
3737 GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount, &g_FontListHead);
3738
3739 /* search in private fonts */
3740 IntLockProcessPrivateFonts(Win32Process);
3741 GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount,
3742 &Win32Process->PrivateFontListHead);
3743 IntUnLockProcessPrivateFonts(Win32Process);
3744 IntUnLockFreeType();
3745
3746 if (LogFont->lfFaceName[0] != UNICODE_NULL)
3747 {
3748 /* it's already matched to the exact name and charset if the name
3749 was specified at here, then so don't scan more for another name */
3750 break;
3751 }
3752 }
3753
3754 return TRUE;
3755 }
3756
3757 BOOL
3758 FASTCALL
ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)3759 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
3760 {
3761 if ( lprs )
3762 {
3763 lprs->nSize = sizeof(RASTERIZER_STATUS);
3764 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
3765 lprs->nLanguageID = gusLanguageID;
3766 return TRUE;
3767 }
3768 EngSetLastError(ERROR_INVALID_PARAMETER);
3769 return FALSE;
3770 }
3771
3772 static DWORD
IntGetHash(IN LPCVOID pv,IN DWORD cdw)3773 IntGetHash(IN LPCVOID pv, IN DWORD cdw)
3774 {
3775 DWORD dwHash = cdw;
3776 const DWORD *pdw = pv;
3777
3778 while (cdw-- > 0)
3779 {
3780 dwHash *= 3;
3781 dwHash ^= *pdw++;
3782 }
3783
3784 return dwHash;
3785 }
3786
3787 static FT_BitmapGlyph
IntFindGlyphCache(IN const FONT_CACHE_ENTRY * pCache)3788 IntFindGlyphCache(IN const FONT_CACHE_ENTRY *pCache)
3789 {
3790 PLIST_ENTRY CurrentEntry;
3791 PFONT_CACHE_ENTRY FontEntry;
3792 DWORD dwHash = pCache->dwHash;
3793
3794 ASSERT_FREETYPE_LOCK_HELD();
3795
3796 for (CurrentEntry = g_FontCacheListHead.Flink;
3797 CurrentEntry != &g_FontCacheListHead;
3798 CurrentEntry = CurrentEntry->Flink)
3799 {
3800 FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
3801 if (FontEntry->dwHash == dwHash &&
3802 FontEntry->Hashed.GlyphIndex == pCache->Hashed.GlyphIndex &&
3803 FontEntry->Hashed.Face == pCache->Hashed.Face &&
3804 FontEntry->Hashed.lfHeight == pCache->Hashed.lfHeight &&
3805 FontEntry->Hashed.lfWidth == pCache->Hashed.lfWidth &&
3806 FontEntry->Hashed.AspectValue == pCache->Hashed.AspectValue &&
3807 memcmp(&FontEntry->Hashed.matTransform, &pCache->Hashed.matTransform,
3808 sizeof(FT_Matrix)) == 0)
3809 {
3810 break;
3811 }
3812 }
3813
3814 if (CurrentEntry == &g_FontCacheListHead)
3815 {
3816 return NULL;
3817 }
3818
3819 RemoveEntryList(CurrentEntry);
3820 InsertHeadList(&g_FontCacheListHead, CurrentEntry);
3821 return FontEntry->BitmapGlyph;
3822 }
3823
3824 static FT_BitmapGlyph
IntGetBitmapGlyphWithCache(IN OUT PFONT_CACHE_ENTRY Cache,IN FT_GlyphSlot GlyphSlot)3825 IntGetBitmapGlyphWithCache(
3826 IN OUT PFONT_CACHE_ENTRY Cache,
3827 IN FT_GlyphSlot GlyphSlot)
3828 {
3829 FT_Glyph GlyphCopy;
3830 INT error;
3831 PFONT_CACHE_ENTRY NewEntry;
3832 FT_Bitmap AlignedBitmap;
3833 FT_BitmapGlyph BitmapGlyph;
3834
3835 ASSERT_FREETYPE_LOCK_HELD();
3836
3837 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
3838 if (error)
3839 {
3840 DPRINT1("Failure caching glyph.\n");
3841 return NULL;
3842 };
3843
3844 error = FT_Glyph_To_Bitmap(&GlyphCopy, Cache->Hashed.Aspect.RenderMode, 0, 1);
3845 if (error)
3846 {
3847 FT_Done_Glyph(GlyphCopy);
3848 DPRINT1("Failure rendering glyph.\n");
3849 return NULL;
3850 };
3851
3852 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
3853 if (!NewEntry)
3854 {
3855 DPRINT1("Alloc failure caching glyph.\n");
3856 FT_Done_Glyph(GlyphCopy);
3857 return NULL;
3858 }
3859
3860 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
3861 FT_Bitmap_New(&AlignedBitmap);
3862 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
3863 {
3864 DPRINT1("Conversion failed\n");
3865 ExFreePoolWithTag(NewEntry, TAG_FONT);
3866 FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
3867 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
3868 return NULL;
3869 }
3870
3871 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
3872 BitmapGlyph->bitmap = AlignedBitmap;
3873
3874 NewEntry->BitmapGlyph = BitmapGlyph;
3875 NewEntry->dwHash = Cache->dwHash;
3876 NewEntry->Hashed = Cache->Hashed;
3877
3878 InsertHeadList(&g_FontCacheListHead, &NewEntry->ListEntry);
3879 if (++g_FontCacheNumEntries > MAX_FONT_CACHE)
3880 {
3881 NewEntry = CONTAINING_RECORD(g_FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
3882 RemoveCachedEntry(NewEntry);
3883 }
3884
3885 return BitmapGlyph;
3886 }
3887
3888
get_native_glyph_outline(FT_Outline * outline,unsigned int buflen,char * buf)3889 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3890 {
3891 TTPOLYGONHEADER *pph;
3892 TTPOLYCURVE *ppc;
3893 int needed = 0, point = 0, contour, first_pt;
3894 unsigned int pph_start, cpfx;
3895 DWORD type;
3896
3897 for (contour = 0; contour < outline->n_contours; contour++)
3898 {
3899 /* Ignore contours containing one point */
3900 if (point == outline->contours[contour])
3901 {
3902 point++;
3903 continue;
3904 }
3905
3906 pph_start = needed;
3907 pph = (TTPOLYGONHEADER *)(buf + needed);
3908 first_pt = point;
3909 if (buf)
3910 {
3911 pph->dwType = TT_POLYGON_TYPE;
3912 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3913 }
3914 needed += sizeof(*pph);
3915 point++;
3916 while (point <= outline->contours[contour])
3917 {
3918 ppc = (TTPOLYCURVE *)(buf + needed);
3919 type = (outline->tags[point] & FT_Curve_Tag_On) ?
3920 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3921 cpfx = 0;
3922 do
3923 {
3924 if (buf)
3925 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3926 cpfx++;
3927 point++;
3928 } while (point <= outline->contours[contour] &&
3929 (outline->tags[point] & FT_Curve_Tag_On) ==
3930 (outline->tags[point-1] & FT_Curve_Tag_On));
3931 /* At the end of a contour Windows adds the start point, but
3932 only for Beziers */
3933 if (point > outline->contours[contour] &&
3934 !(outline->tags[point-1] & FT_Curve_Tag_On))
3935 {
3936 if (buf)
3937 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3938 cpfx++;
3939 }
3940 else if (point <= outline->contours[contour] &&
3941 outline->tags[point] & FT_Curve_Tag_On)
3942 {
3943 /* add closing pt for bezier */
3944 if (buf)
3945 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3946 cpfx++;
3947 point++;
3948 }
3949 if (buf)
3950 {
3951 ppc->wType = type;
3952 ppc->cpfx = cpfx;
3953 }
3954 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3955 }
3956 if (buf)
3957 pph->cb = needed - pph_start;
3958 }
3959 return needed;
3960 }
3961
get_bezier_glyph_outline(FT_Outline * outline,unsigned int buflen,char * buf)3962 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3963 {
3964 /* Convert the quadratic Beziers to cubic Beziers.
3965 The parametric eqn for a cubic Bezier is, from PLRM:
3966 r(t) = at^3 + bt^2 + ct + r0
3967 with the control points:
3968 r1 = r0 + c/3
3969 r2 = r1 + (c + b)/3
3970 r3 = r0 + c + b + a
3971
3972 A quadratic Bezier has the form:
3973 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3974
3975 So equating powers of t leads to:
3976 r1 = 2/3 p1 + 1/3 p0
3977 r2 = 2/3 p1 + 1/3 p2
3978 and of course r0 = p0, r3 = p2
3979 */
3980 int contour, point = 0, first_pt;
3981 TTPOLYGONHEADER *pph;
3982 TTPOLYCURVE *ppc;
3983 DWORD pph_start, cpfx, type;
3984 FT_Vector cubic_control[4];
3985 unsigned int needed = 0;
3986
3987 for (contour = 0; contour < outline->n_contours; contour++)
3988 {
3989 pph_start = needed;
3990 pph = (TTPOLYGONHEADER *)(buf + needed);
3991 first_pt = point;
3992 if (buf)
3993 {
3994 pph->dwType = TT_POLYGON_TYPE;
3995 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3996 }
3997 needed += sizeof(*pph);
3998 point++;
3999 while (point <= outline->contours[contour])
4000 {
4001 ppc = (TTPOLYCURVE *)(buf + needed);
4002 type = (outline->tags[point] & FT_Curve_Tag_On) ?
4003 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4004 cpfx = 0;
4005 do
4006 {
4007 if (type == TT_PRIM_LINE)
4008 {
4009 if (buf)
4010 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4011 cpfx++;
4012 point++;
4013 }
4014 else
4015 {
4016 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4017 so cpfx = 3n */
4018
4019 /* FIXME: Possible optimization in endpoint calculation
4020 if there are two consecutive curves */
4021 cubic_control[0] = outline->points[point-1];
4022 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
4023 {
4024 cubic_control[0].x += outline->points[point].x + 1;
4025 cubic_control[0].y += outline->points[point].y + 1;
4026 cubic_control[0].x >>= 1;
4027 cubic_control[0].y >>= 1;
4028 }
4029 if (point+1 > outline->contours[contour])
4030 cubic_control[3] = outline->points[first_pt];
4031 else
4032 {
4033 cubic_control[3] = outline->points[point+1];
4034 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
4035 {
4036 cubic_control[3].x += outline->points[point].x + 1;
4037 cubic_control[3].y += outline->points[point].y + 1;
4038 cubic_control[3].x >>= 1;
4039 cubic_control[3].y >>= 1;
4040 }
4041 }
4042 /* r1 = 1/3 p0 + 2/3 p1
4043 r2 = 1/3 p2 + 2/3 p1 */
4044 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4045 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4046 cubic_control[2] = cubic_control[1];
4047 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4048 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4049 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4050 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4051 if (buf)
4052 {
4053 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4054 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4055 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4056 }
4057 cpfx += 3;
4058 point++;
4059 }
4060 } while (point <= outline->contours[contour] &&
4061 (outline->tags[point] & FT_Curve_Tag_On) ==
4062 (outline->tags[point-1] & FT_Curve_Tag_On));
4063 /* At the end of a contour Windows adds the start point,
4064 but only for Beziers and we've already done that.
4065 */
4066 if (point <= outline->contours[contour] &&
4067 outline->tags[point] & FT_Curve_Tag_On)
4068 {
4069 /* This is the closing pt of a bezier, but we've already
4070 added it, so just inc point and carry on */
4071 point++;
4072 }
4073 if (buf)
4074 {
4075 ppc->wType = type;
4076 ppc->cpfx = cpfx;
4077 }
4078 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4079 }
4080 if (buf)
4081 pph->cb = needed - pph_start;
4082 }
4083 return needed;
4084 }
4085
4086 static FT_Error
IntRequestFontSize(PDC dc,PFONTGDI FontGDI,LONG lfWidth,LONG lfHeight)4087 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
4088 {
4089 FT_Error error;
4090 FT_Size_RequestRec req;
4091 FT_Face face = FontGDI->SharedFace->Face;
4092 TT_OS2 *pOS2;
4093 TT_HoriHeader *pHori;
4094 FT_WinFNT_HeaderRec WinFNT;
4095 LONG Ascent, Descent, Sum, EmHeight, Width64;
4096
4097 lfWidth = abs(lfWidth);
4098 if (lfHeight == 0)
4099 {
4100 if (lfWidth == 0)
4101 {
4102 DPRINT("lfHeight and lfWidth are zero.\n");
4103 lfHeight = -16;
4104 }
4105 else
4106 {
4107 lfHeight = lfWidth;
4108 }
4109 }
4110
4111 if (lfHeight == -1)
4112 lfHeight = -2;
4113
4114 if (FontGDI->Magic == FONTGDI_MAGIC &&
4115 FontGDI->lfHeight == lfHeight &&
4116 FontGDI->lfWidth == lfWidth)
4117 {
4118 return 0; /* Cached */
4119 }
4120
4121 ASSERT_FREETYPE_LOCK_HELD();
4122 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
4123 pHori = (TT_HoriHeader *)FT_Get_Sfnt_Table(face, FT_SFNT_HHEA);
4124
4125 if (!pOS2 || !pHori)
4126 {
4127 error = FT_Get_WinFNT_Header(face, &WinFNT);
4128 if (error)
4129 {
4130 DPRINT1("%s: Failed to request font size.\n", face->family_name);
4131 ASSERT(FALSE);
4132 return error;
4133 }
4134
4135 FontGDI->tmHeight = WinFNT.pixel_height;
4136 FontGDI->tmAscent = WinFNT.ascent;
4137 FontGDI->tmDescent = FontGDI->tmHeight - FontGDI->tmAscent;
4138 FontGDI->tmInternalLeading = WinFNT.internal_leading;
4139 FontGDI->Magic = FONTGDI_MAGIC;
4140 FontGDI->lfHeight = lfHeight;
4141 FontGDI->lfWidth = lfWidth;
4142 return 0;
4143 }
4144
4145 /*
4146 * NOTE: We cast TT_OS2.usWinAscent and TT_OS2.usWinDescent to signed FT_Short.
4147 * Why? See: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswindescent
4148 *
4149 * > usWinDescent is "usually" a positive value ...
4150 *
4151 * We can read it as "not always". See CORE-14994.
4152 * See also: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fsselection
4153 */
4154 #define FM_SEL_USE_TYPO_METRICS 0x80
4155 if (lfHeight > 0)
4156 {
4157 /* case (A): lfHeight is positive */
4158 Sum = (FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent;
4159 if (Sum == 0 || (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS))
4160 {
4161 Ascent = pHori->Ascender;
4162 Descent = -pHori->Descender;
4163 Sum = Ascent + Descent;
4164 }
4165 else
4166 {
4167 Ascent = (FT_Short)pOS2->usWinAscent;
4168 Descent = (FT_Short)pOS2->usWinDescent;
4169 }
4170
4171 FontGDI->tmAscent = FT_MulDiv(lfHeight, Ascent, Sum);
4172 FontGDI->tmDescent = FT_MulDiv(lfHeight, Descent, Sum);
4173 FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
4174 FontGDI->tmInternalLeading = FontGDI->tmHeight - FT_MulDiv(lfHeight, face->units_per_EM, Sum);
4175 }
4176 else if (lfHeight < 0)
4177 {
4178 /* case (B): lfHeight is negative */
4179 if (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS)
4180 {
4181 FontGDI->tmAscent = FT_MulDiv(-lfHeight, pHori->Ascender, face->units_per_EM);
4182 FontGDI->tmDescent = FT_MulDiv(-lfHeight, -pHori->Descender, face->units_per_EM);
4183 }
4184 else
4185 {
4186 FontGDI->tmAscent = FT_MulDiv(-lfHeight, (FT_Short)pOS2->usWinAscent, face->units_per_EM);
4187 FontGDI->tmDescent = FT_MulDiv(-lfHeight, (FT_Short)pOS2->usWinDescent, face->units_per_EM);
4188 }
4189 FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
4190 FontGDI->tmInternalLeading = FontGDI->tmHeight + lfHeight;
4191 }
4192 #undef FM_SEL_USE_TYPO_METRICS
4193
4194 FontGDI->Magic = FONTGDI_MAGIC;
4195 FontGDI->lfHeight = lfHeight;
4196 FontGDI->lfWidth = lfWidth;
4197
4198 EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
4199 EmHeight = max(EmHeight, 1);
4200 EmHeight = min(EmHeight, USHORT_MAX);
4201
4202 #if 1
4203 /* I think this is wrong implementation but its test result is better. */
4204 if (lfWidth != 0)
4205 Width64 = FT_MulDiv(lfWidth, face->units_per_EM, pOS2->xAvgCharWidth) << 6;
4206 else
4207 Width64 = 0;
4208 #else
4209 /* I think this is correct implementation but it is mismatching to the
4210 other metric functions. The test result is bad. */
4211 if (lfWidth != 0)
4212 Width64 = (FT_MulDiv(lfWidth, 96 * 5, 72 * 3) << 6); /* ??? FIXME */
4213 else
4214 Width64 = 0;
4215 #endif
4216
4217 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
4218 req.width = Width64;
4219 req.height = (EmHeight << 6);
4220 req.horiResolution = 0;
4221 req.vertResolution = 0;
4222 return FT_Request_Size(face, &req);
4223 }
4224
4225 BOOL
4226 FASTCALL
TextIntUpdateSize(PDC dc,PTEXTOBJ TextObj,PFONTGDI FontGDI,BOOL bDoLock)4227 TextIntUpdateSize(PDC dc,
4228 PTEXTOBJ TextObj,
4229 PFONTGDI FontGDI,
4230 BOOL bDoLock)
4231 {
4232 FT_Face face;
4233 INT error, n;
4234 FT_CharMap charmap, found;
4235 LOGFONTW *plf;
4236
4237 if (bDoLock)
4238 IntLockFreeType();
4239
4240 face = FontGDI->SharedFace->Face;
4241 if (face->charmap == NULL)
4242 {
4243 DPRINT("WARNING: No charmap selected!\n");
4244 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
4245
4246 found = NULL;
4247 for (n = 0; n < face->num_charmaps; n++)
4248 {
4249 charmap = face->charmaps[n];
4250 if (charmap->encoding == FT_ENCODING_UNICODE)
4251 {
4252 found = charmap;
4253 break;
4254 }
4255 }
4256 if (!found)
4257 {
4258 for (n = 0; n < face->num_charmaps; n++)
4259 {
4260 charmap = face->charmaps[n];
4261 if (charmap->platform_id == TT_PLATFORM_APPLE_UNICODE)
4262 {
4263 found = charmap;
4264 break;
4265 }
4266 }
4267 }
4268 if (!found)
4269 {
4270 for (n = 0; n < face->num_charmaps; n++)
4271 {
4272 charmap = face->charmaps[n];
4273 if (charmap->encoding == FT_ENCODING_MS_SYMBOL)
4274 {
4275 found = charmap;
4276 break;
4277 }
4278 }
4279 }
4280 if (!found && face->num_charmaps > 0)
4281 {
4282 found = face->charmaps[0];
4283 }
4284 if (!found)
4285 {
4286 DPRINT1("WARNING: Could not find desired charmap!\n");
4287 }
4288 else
4289 {
4290 DPRINT("Found charmap encoding: %i\n", found->encoding);
4291 error = FT_Set_Charmap(face, found);
4292 if (error)
4293 {
4294 DPRINT1("WARNING: Could not set the charmap!\n");
4295 }
4296 }
4297 }
4298
4299 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4300
4301 error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
4302
4303 if (bDoLock)
4304 IntUnLockFreeType();
4305
4306 if (error)
4307 {
4308 DPRINT1("Error in setting pixel sizes: %d\n", error);
4309 return FALSE;
4310 }
4311
4312 return TRUE;
4313 }
4314
4315 static inline FT_UInt FASTCALL
get_glyph_index_symbol(FT_Face ft_face,UINT glyph)4316 get_glyph_index_symbol(FT_Face ft_face, UINT glyph)
4317 {
4318 FT_UInt ret;
4319
4320 if (glyph < 0x100) glyph += 0xf000;
4321 /* there are a number of old pre-Unicode "broken" TTFs, which
4322 do have symbols at U+00XX instead of U+f0XX */
4323 if (!(ret = FT_Get_Char_Index(ft_face, glyph)))
4324 ret = FT_Get_Char_Index(ft_face, glyph - 0xf000);
4325
4326 return ret;
4327 }
4328
4329 static inline FT_UInt FASTCALL
get_glyph_index(FT_Face ft_face,UINT glyph)4330 get_glyph_index(FT_Face ft_face, UINT glyph)
4331 {
4332 FT_UInt ret;
4333
4334 if (face_has_symbol_charmap(ft_face))
4335 {
4336 ret = get_glyph_index_symbol(ft_face, glyph);
4337 if (ret != 0)
4338 return ret;
4339 }
4340
4341 return FT_Get_Char_Index(ft_face, glyph);
4342 }
4343
4344 static inline FT_UInt FASTCALL
get_glyph_index_flagged(FT_Face face,FT_ULong code,BOOL fCodeAsIndex)4345 get_glyph_index_flagged(FT_Face face, FT_ULong code, BOOL fCodeAsIndex)
4346 {
4347 return (fCodeAsIndex ? code : get_glyph_index(face, code));
4348 }
4349
4350 static inline VOID
FontLink_Chain_Dump(_In_ PFONTLINK_CHAIN pChain)4351 FontLink_Chain_Dump(
4352 _In_ PFONTLINK_CHAIN pChain)
4353 {
4354 #if 0
4355 PLIST_ENTRY Entry, Head;
4356 PFONTLINK pFontLink;
4357 INT iLink = 0;
4358
4359 DPRINT1("%S, %p, %p\n", pChain->LogFont.lfFaceName, pChain->pBaseTextObj, pChain->pDefFace);
4360
4361 Head = &pChain->FontLinkList;
4362 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
4363 {
4364 pFontLink = CONTAINING_RECORD(Entry, FONTLINK, ListEntry);
4365 DPRINT1("FontLink #%d: %p, %d, %S, %p, %p\n",
4366 iLink, pFontLink, pFontLink->bIgnore, pFontLink->LogFont.lfFaceName,
4367 pFontLink->pFontGDI, pFontLink->SharedFace);
4368 ++iLink;
4369 }
4370 #endif
4371 }
4372
4373 /// Search the target glyph and update the current font info.
4374 /// @return The glyph index
4375 static UINT
FontLink_Chain_FindGlyph(_Inout_ PFONTLINK_CHAIN pChain,_Out_ PFONT_CACHE_ENTRY pCache,_Inout_ FT_Face * pFace,_In_ UINT code,_In_ BOOL fCodeAsIndex)4376 FontLink_Chain_FindGlyph(
4377 _Inout_ PFONTLINK_CHAIN pChain,
4378 _Out_ PFONT_CACHE_ENTRY pCache,
4379 _Inout_ FT_Face *pFace,
4380 _In_ UINT code,
4381 _In_ BOOL fCodeAsIndex)
4382 {
4383 PFONTLINK pFontLink;
4384 PLIST_ENTRY Entry, Head;
4385 UINT index;
4386 FT_Face face;
4387
4388 // Try the default font at first
4389 index = get_glyph_index_flagged(pChain->pDefFace, code, fCodeAsIndex);
4390 if (index)
4391 {
4392 DPRINT("code: 0x%08X, index: 0x%08X, fCodeAsIndex:%d\n", code, index, fCodeAsIndex);
4393 pCache->Hashed.Face = *pFace = pChain->pDefFace;
4394 return index; // The glyph is found on the default font
4395 }
4396
4397 if (!FontLink_Chain_IsPopulated(pChain)) // The chain is not populated yet
4398 {
4399 FontLink_Chain_Populate(pChain);
4400 FontLink_Chain_Dump(pChain);
4401 }
4402
4403 // Now the chain is populated. Looking for the target glyph...
4404 Head = &pChain->FontLinkList;
4405 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
4406 {
4407 pFontLink = CONTAINING_RECORD(Entry, FONTLINK, ListEntry);
4408 if (!FontLink_PrepareFontInfo(pFontLink))
4409 continue; // This link is not useful, check the next one
4410
4411 face = pFontLink->SharedFace->Face;
4412 index = get_glyph_index(face, code);
4413 if (!index)
4414 continue; // The glyph does not exist, continue searching
4415
4416 // The target glyph is found in the chain
4417 DPRINT("code: 0x%08X, index: 0x%08X\n", code, index);
4418 pCache->Hashed.Face = *pFace = face;
4419 FT_Set_Transform(face, &pCache->Hashed.matTransform, NULL);
4420 return index;
4421 }
4422
4423 // No target glyph found in the chain: use default glyph
4424 code = s_chFontLinkDefaultChar;
4425 index = get_glyph_index(*pFace, code);
4426 DPRINT("code: 0x%08X, index: 0x%08X\n", code, index);
4427 pCache->Hashed.Face = *pFace = pChain->pDefFace;
4428 return index;
4429 }
4430
4431 /*
4432 * Based on WineEngGetGlyphOutline
4433 */
4434 ULONG
4435 FASTCALL
ftGdiGetGlyphOutline(PDC dc,WCHAR wch,UINT iFormat,LPGLYPHMETRICS pgm,ULONG cjBuf,PVOID pvBuf,LPMAT2 pmat2,BOOL bIgnoreRotation)4436 ftGdiGetGlyphOutline(
4437 PDC dc,
4438 WCHAR wch,
4439 UINT iFormat,
4440 LPGLYPHMETRICS pgm,
4441 ULONG cjBuf,
4442 PVOID pvBuf,
4443 LPMAT2 pmat2,
4444 BOOL bIgnoreRotation)
4445 {
4446 PDC_ATTR pdcattr;
4447 PTEXTOBJ TextObj;
4448 PFONTGDI FontGDI;
4449 HFONT hFont = 0;
4450 GLYPHMETRICS gm;
4451 ULONG Size;
4452 FT_Face ft_face;
4453 FT_UInt glyph_index;
4454 DWORD width, height, pitch, needed = 0;
4455 FT_Bitmap ft_bitmap;
4456 FT_Error error;
4457 INT left, right, top = 0, bottom = 0;
4458 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4459 FLOATOBJ eM11, widthRatio, eTemp;
4460 FT_Matrix mat, transMat = identityMat;
4461 BOOL needsTransform = FALSE;
4462 INT orientation;
4463 LONG aveWidth;
4464 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
4465 OUTLINETEXTMETRICW *potm;
4466 XFORMOBJ xo;
4467 XFORML xform;
4468 LOGFONTW *plf;
4469
4470 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
4471 cjBuf, pvBuf, pmat2);
4472
4473 pdcattr = dc->pdcattr;
4474
4475 XFORMOBJ_vInit(&xo, &dc->pdcattr->mxWorldToDevice);
4476 XFORMOBJ_iGetXform(&xo, &xform);
4477 FLOATOBJ_SetFloat(&eM11, xform.eM11);
4478
4479 hFont = pdcattr->hlfntNew;
4480 TextObj = RealizeFontInit(hFont);
4481
4482 if (!TextObj)
4483 {
4484 EngSetLastError(ERROR_INVALID_HANDLE);
4485 return GDI_ERROR;
4486 }
4487 FontGDI = ObjToGDI(TextObj->Font, FONT);
4488 ft_face = FontGDI->SharedFace->Face;
4489
4490 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4491 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
4492 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
4493
4494 ASSERT_FREETYPE_LOCK_NOT_HELD();
4495 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL, FALSE);
4496 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
4497 if (!potm)
4498 {
4499 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4500 TEXTOBJ_UnlockText(TextObj);
4501 return GDI_ERROR;
4502 }
4503 ASSERT_FREETYPE_LOCK_NOT_HELD();
4504 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm, FALSE);
4505 if (!Size)
4506 {
4507 /* FIXME: last error? */
4508 ExFreePoolWithTag(potm, GDITAG_TEXT);
4509 TEXTOBJ_UnlockText(TextObj);
4510 return GDI_ERROR;
4511 }
4512
4513 IntLockFreeType();
4514 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
4515 IntMatrixFromMx(&mat, DC_pmxWorldToDevice(dc));
4516 FT_Set_Transform(ft_face, &mat, NULL);
4517
4518 TEXTOBJ_UnlockText(TextObj);
4519
4520 glyph_index = get_glyph_index_flagged(ft_face, wch, (iFormat & GGO_GLYPH_INDEX));
4521 iFormat &= ~GGO_GLYPH_INDEX;
4522
4523 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
4524 load_flags |= FT_LOAD_NO_BITMAP;
4525
4526 if (iFormat & GGO_UNHINTED)
4527 {
4528 load_flags |= FT_LOAD_NO_HINTING;
4529 iFormat &= ~GGO_UNHINTED;
4530 }
4531
4532 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
4533 if (error)
4534 {
4535 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
4536 IntUnLockFreeType();
4537 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
4538 return GDI_ERROR;
4539 }
4540 IntUnLockFreeType();
4541
4542 FLOATOBJ_Set1(&widthRatio);
4543 if (aveWidth && potm)
4544 {
4545 // widthRatio = aveWidth * eM11 / potm->otmTextMetrics.tmAveCharWidth
4546 FLOATOBJ_SetLong(&widthRatio, aveWidth);
4547 FLOATOBJ_Mul(&widthRatio, &eM11);
4548 FLOATOBJ_DivLong(&widthRatio, potm->otmTextMetrics.tmAveCharWidth);
4549 }
4550
4551 //left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
4552 FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiBearingX);
4553 FLOATOBJ_Mul(&eTemp, &widthRatio);
4554 left = FLOATOBJ_GetLong(&eTemp) & -64;
4555
4556 //right = (INT)((ft_face->glyph->metrics.horiBearingX +
4557 // ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
4558 FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiBearingX * ft_face->glyph->metrics.width);
4559 FLOATOBJ_Mul(&eTemp, &widthRatio);
4560 FLOATOBJ_AddLong(&eTemp, 63);
4561 right = FLOATOBJ_GetLong(&eTemp) & -64;
4562
4563 //adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
4564 FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiAdvance);
4565 FLOATOBJ_Mul(&eTemp, &widthRatio);
4566 FLOATOBJ_AddLong(&eTemp, 63);
4567 adv = FLOATOBJ_GetLong(&eTemp) >> 6;
4568
4569 lsb = left >> 6;
4570 bbx = (right - left) >> 6;
4571
4572 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
4573
4574 IntLockFreeType();
4575
4576 /* Width scaling transform */
4577 if (!FLOATOBJ_Equal1(&widthRatio))
4578 {
4579 FT_Matrix scaleMat;
4580
4581 eTemp = widthRatio;
4582 FLOATOBJ_MulLong(&eTemp, 1 << 16);
4583
4584 scaleMat.xx = FLOATOBJ_GetLong(&eTemp);
4585 scaleMat.xy = 0;
4586 scaleMat.yx = 0;
4587 scaleMat.yy = INT_TO_FIXED(1);
4588 FT_Matrix_Multiply(&scaleMat, &transMat);
4589 needsTransform = TRUE;
4590 }
4591
4592 /* World transform */
4593 {
4594 FT_Matrix ftmatrix;
4595 PMATRIX pmx = DC_pmxWorldToDevice(dc);
4596
4597 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
4598 IntMatrixFromMx(&ftmatrix, pmx);
4599
4600 if (memcmp(&ftmatrix, &identityMat, sizeof(identityMat)) != 0)
4601 {
4602 FT_Matrix_Multiply(&ftmatrix, &transMat);
4603 needsTransform = TRUE;
4604 }
4605 }
4606
4607 /* Rotation transform */
4608 if (orientation)
4609 {
4610 FT_Matrix rotationMat;
4611 DPRINT("Rotation Trans!\n");
4612 IntEscapeMatrix(&rotationMat, orientation);
4613 FT_Matrix_Multiply(&rotationMat, &transMat);
4614 needsTransform = TRUE;
4615 }
4616
4617 /* Extra transformation specified by caller */
4618 if (pmat2)
4619 {
4620 FT_Matrix extraMat;
4621 DPRINT("MAT2 Matrix Trans!\n");
4622 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
4623 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
4624 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
4625 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
4626 FT_Matrix_Multiply(&extraMat, &transMat);
4627 needsTransform = TRUE;
4628 }
4629
4630 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
4631
4632 if (!needsTransform)
4633 {
4634 DPRINT("No Need to be Transformed!\n");
4635 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4636 bottom = (ft_face->glyph->metrics.horiBearingY -
4637 ft_face->glyph->metrics.height) & -64;
4638 gm.gmCellIncX = adv;
4639 gm.gmCellIncY = 0;
4640 }
4641 else
4642 {
4643 INT xc, yc;
4644 FT_Vector vec;
4645 for (xc = 0; xc < 2; xc++)
4646 {
4647 for (yc = 0; yc < 2; yc++)
4648 {
4649 vec.x = (ft_face->glyph->metrics.horiBearingX +
4650 xc * ft_face->glyph->metrics.width);
4651 vec.y = ft_face->glyph->metrics.horiBearingY -
4652 yc * ft_face->glyph->metrics.height;
4653 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
4654 FT_Vector_Transform(&vec, &transMat);
4655 if (xc == 0 && yc == 0)
4656 {
4657 left = right = vec.x;
4658 top = bottom = vec.y;
4659 }
4660 else
4661 {
4662 if (vec.x < left) left = vec.x;
4663 else if (vec.x > right) right = vec.x;
4664 if (vec.y < bottom) bottom = vec.y;
4665 else if (vec.y > top) top = vec.y;
4666 }
4667 }
4668 }
4669 left = left & -64;
4670 right = (right + 63) & -64;
4671 bottom = bottom & -64;
4672 top = (top + 63) & -64;
4673
4674 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4675 vec.x = ft_face->glyph->metrics.horiAdvance;
4676 vec.y = 0;
4677 FT_Vector_Transform(&vec, &transMat);
4678 gm.gmCellIncX = (vec.x+63) >> 6;
4679 gm.gmCellIncY = -((vec.y+63) >> 6);
4680 }
4681 gm.gmBlackBoxX = (right - left) >> 6;
4682 gm.gmBlackBoxY = (top - bottom) >> 6;
4683 gm.gmptGlyphOrigin.x = left >> 6;
4684 gm.gmptGlyphOrigin.y = top >> 6;
4685
4686 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
4687 gm.gmCellIncX, gm.gmCellIncY,
4688 gm.gmBlackBoxX, gm.gmBlackBoxY,
4689 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
4690
4691 IntUnLockFreeType();
4692
4693 if (iFormat == GGO_METRICS)
4694 {
4695 DPRINT("GGO_METRICS Exit!\n");
4696 *pgm = gm;
4697 return 1; /* FIXME */
4698 }
4699
4700 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
4701 {
4702 DPRINT1("Loaded a bitmap\n");
4703 return GDI_ERROR;
4704 }
4705
4706 switch (iFormat)
4707 {
4708 case GGO_BITMAP:
4709 {
4710 width = gm.gmBlackBoxX;
4711 height = gm.gmBlackBoxY;
4712 pitch = ((width + 31) >> 5) << 2;
4713 needed = pitch * height;
4714
4715 if (!pvBuf || !cjBuf) break;
4716 if (!needed) return GDI_ERROR; /* empty glyph */
4717 if (needed > cjBuf)
4718 return GDI_ERROR;
4719
4720 switch (ft_face->glyph->format)
4721 {
4722 case ft_glyph_format_bitmap:
4723 {
4724 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
4725 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
4726 INT h = min( height, ft_face->glyph->bitmap.rows );
4727 while (h--)
4728 {
4729 RtlCopyMemory(dst, src, w);
4730 src += ft_face->glyph->bitmap.pitch;
4731 dst += pitch;
4732 }
4733 break;
4734 }
4735
4736 case ft_glyph_format_outline:
4737 {
4738 ft_bitmap.width = width;
4739 ft_bitmap.rows = height;
4740 ft_bitmap.pitch = pitch;
4741 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
4742 ft_bitmap.buffer = pvBuf;
4743
4744 IntLockFreeType();
4745 if (needsTransform)
4746 {
4747 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4748 }
4749 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4750 /* Note: FreeType will only set 'black' bits for us. */
4751 RtlZeroMemory(pvBuf, needed);
4752 FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
4753 IntUnLockFreeType();
4754 break;
4755 }
4756
4757 default:
4758 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
4759 return GDI_ERROR;
4760 }
4761
4762 break;
4763 }
4764
4765 case GGO_GRAY2_BITMAP:
4766 case GGO_GRAY4_BITMAP:
4767 case GGO_GRAY8_BITMAP:
4768 {
4769 unsigned int mult, row, col;
4770 BYTE *start, *ptr;
4771
4772 width = gm.gmBlackBoxX;
4773 height = gm.gmBlackBoxY;
4774 pitch = (width + 3) / 4 * 4;
4775 needed = pitch * height;
4776
4777 if (!pvBuf || !cjBuf) break;
4778 if (!needed) return GDI_ERROR; /* empty glyph */
4779 if (needed > cjBuf)
4780 return GDI_ERROR;
4781
4782 switch (ft_face->glyph->format)
4783 {
4784 case ft_glyph_format_bitmap:
4785 {
4786 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
4787 INT h = min( height, ft_face->glyph->bitmap.rows );
4788 INT x;
4789 while (h--)
4790 {
4791 for (x = 0; (UINT)x < pitch; x++)
4792 {
4793 if (x < ft_face->glyph->bitmap.width)
4794 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4795 else
4796 dst[x] = 0;
4797 }
4798 src += ft_face->glyph->bitmap.pitch;
4799 dst += pitch;
4800 }
4801 break;
4802 }
4803 case ft_glyph_format_outline:
4804 {
4805 ft_bitmap.width = width;
4806 ft_bitmap.rows = height;
4807 ft_bitmap.pitch = pitch;
4808 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
4809 ft_bitmap.buffer = pvBuf;
4810
4811 IntLockFreeType();
4812 if (needsTransform)
4813 {
4814 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4815 }
4816 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4817 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
4818 FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
4819 IntUnLockFreeType();
4820
4821 if (iFormat == GGO_GRAY2_BITMAP)
4822 mult = 4;
4823 else if (iFormat == GGO_GRAY4_BITMAP)
4824 mult = 16;
4825 else if (iFormat == GGO_GRAY8_BITMAP)
4826 mult = 64;
4827 else
4828 {
4829 return GDI_ERROR;
4830 }
4831
4832 start = pvBuf;
4833 for (row = 0; row < height; row++)
4834 {
4835 ptr = start;
4836 for (col = 0; col < width; col++, ptr++)
4837 {
4838 *ptr = (((int)*ptr) * mult + 128) / 256;
4839 }
4840 start += pitch;
4841 }
4842
4843 break;
4844 }
4845 default:
4846 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
4847 return GDI_ERROR;
4848 }
4849
4850 break;
4851 }
4852
4853 case GGO_NATIVE:
4854 {
4855 FT_Outline *outline = &ft_face->glyph->outline;
4856
4857 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
4858
4859 IntLockFreeType();
4860 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
4861
4862 needed = get_native_glyph_outline(outline, cjBuf, NULL);
4863
4864 if (!pvBuf || !cjBuf)
4865 {
4866 IntUnLockFreeType();
4867 break;
4868 }
4869 if (needed > cjBuf)
4870 {
4871 IntUnLockFreeType();
4872 return GDI_ERROR;
4873 }
4874 get_native_glyph_outline(outline, cjBuf, pvBuf);
4875 IntUnLockFreeType();
4876 break;
4877 }
4878
4879 case GGO_BEZIER:
4880 {
4881 FT_Outline *outline = &ft_face->glyph->outline;
4882 if (cjBuf == 0) pvBuf = NULL;
4883
4884 if (needsTransform && pvBuf)
4885 {
4886 IntLockFreeType();
4887 FT_Outline_Transform(outline, &transMat);
4888 IntUnLockFreeType();
4889 }
4890 needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
4891
4892 if (!pvBuf || !cjBuf)
4893 break;
4894 if (needed > cjBuf)
4895 return GDI_ERROR;
4896
4897 get_bezier_glyph_outline(outline, cjBuf, pvBuf);
4898 break;
4899 }
4900
4901 default:
4902 DPRINT1("Unsupported format %u\n", iFormat);
4903 return GDI_ERROR;
4904 }
4905
4906 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
4907
4908 if (gm.gmBlackBoxX == 0)
4909 gm.gmBlackBoxX = 1;
4910 if (gm.gmBlackBoxY == 0)
4911 gm.gmBlackBoxY = 1;
4912
4913 *pgm = gm;
4914 return needed;
4915 }
4916
4917 static FT_BitmapGlyph
IntGetRealGlyph(IN OUT PFONT_CACHE_ENTRY Cache)4918 IntGetRealGlyph(
4919 IN OUT PFONT_CACHE_ENTRY Cache)
4920 {
4921 INT error;
4922 FT_GlyphSlot glyph;
4923 FT_BitmapGlyph realglyph;
4924
4925 ASSERT_FREETYPE_LOCK_HELD();
4926
4927 Cache->dwHash = IntGetHash(&Cache->Hashed, sizeof(Cache->Hashed) / sizeof(DWORD));
4928
4929 realglyph = IntFindGlyphCache(Cache);
4930 if (realglyph)
4931 return realglyph;
4932
4933 error = FT_Load_Glyph(Cache->Hashed.Face, Cache->Hashed.GlyphIndex, FT_LOAD_DEFAULT);
4934 if (error)
4935 {
4936 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", Cache->Hashed.GlyphIndex);
4937 return NULL;
4938 }
4939
4940 glyph = Cache->Hashed.Face->glyph;
4941
4942 if (Cache->Hashed.Aspect.Emu.Bold)
4943 FT_GlyphSlot_Embolden(glyph); /* Emulate Bold */
4944
4945 if (Cache->Hashed.Aspect.Emu.Italic)
4946 FT_GlyphSlot_Oblique(glyph); /* Emulate Italic */
4947
4948 realglyph = IntGetBitmapGlyphWithCache(Cache, glyph);
4949
4950 if (!realglyph)
4951 DPRINT1("Failed to render glyph! [index: %d]\n", Cache->Hashed.GlyphIndex);
4952
4953 return realglyph;
4954 }
4955
4956 BOOL
4957 FASTCALL
TextIntGetTextExtentPoint(PDC dc,PTEXTOBJ TextObj,LPCWSTR String,INT Count,ULONG MaxExtent,LPINT Fit,LPINT Dx,LPSIZE Size,FLONG fl)4958 TextIntGetTextExtentPoint(PDC dc,
4959 PTEXTOBJ TextObj,
4960 LPCWSTR String,
4961 INT Count,
4962 ULONG MaxExtent,
4963 LPINT Fit,
4964 LPINT Dx,
4965 LPSIZE Size,
4966 FLONG fl)
4967 {
4968 PFONTGDI FontGDI;
4969 FT_BitmapGlyph realglyph;
4970 INT glyph_index, i, previous, nTenthsOfDegrees;
4971 ULONGLONG TotalWidth64 = 0;
4972 LOGFONTW *plf;
4973 BOOL use_kerning, bVerticalWriting;
4974 LONG ascender, descender;
4975 FONT_CACHE_ENTRY Cache;
4976 DWORD ch0, ch1;
4977 FONTLINK_CHAIN Chain;
4978
4979 FontGDI = ObjToGDI(TextObj->Font, FONT);
4980
4981 Cache.Hashed.Face = FontGDI->SharedFace->Face;
4982 if (NULL != Fit)
4983 {
4984 *Fit = 0;
4985 }
4986
4987 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4988 Cache.Hashed.lfHeight = plf->lfHeight;
4989 Cache.Hashed.lfWidth = plf->lfWidth;
4990 Cache.Hashed.Aspect.Emu.Bold = EMUBOLD_NEEDED(FontGDI->OriginalWeight, plf->lfWeight);
4991 Cache.Hashed.Aspect.Emu.Italic = (plf->lfItalic && !FontGDI->OriginalItalic);
4992
4993 // Check vertical writing (tategaki)
4994 nTenthsOfDegrees = IntNormalizeAngle(plf->lfEscapement - plf->lfOrientation);
4995 bVerticalWriting = ((nTenthsOfDegrees == 90 * 10) || (nTenthsOfDegrees == 270 * 10));
4996
4997 if (IntIsFontRenderingEnabled())
4998 Cache.Hashed.Aspect.RenderMode = (BYTE)IntGetFontRenderMode(plf);
4999 else
5000 Cache.Hashed.Aspect.RenderMode = (BYTE)FT_RENDER_MODE_MONO;
5001
5002 // NOTE: GetTextExtentPoint32 simply ignores lfEscapement and XFORM.
5003 IntLockFreeType();
5004 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
5005 Cache.Hashed.matTransform = identityMat;
5006 FT_Set_Transform(Cache.Hashed.Face, NULL, NULL);
5007
5008 FontLink_Chain_Init(&Chain, TextObj, Cache.Hashed.Face);
5009
5010 use_kerning = FT_HAS_KERNING(Cache.Hashed.Face);
5011 previous = 0;
5012
5013 for (i = 0; i < Count; i++)
5014 {
5015 ch0 = *String++;
5016 if (IS_HIGH_SURROGATE(ch0))
5017 {
5018 ++i;
5019 if (i >= Count)
5020 break;
5021
5022 ch1 = *String++;
5023 if (IS_LOW_SURROGATE(ch1))
5024 ch0 = Utf32FromSurrogatePair(ch0, ch1);
5025 }
5026
5027 glyph_index = FontLink_Chain_FindGlyph(&Chain, &Cache, &Cache.Hashed.Face, ch0,
5028 (fl & GTEF_INDICES));
5029 Cache.Hashed.GlyphIndex = glyph_index;
5030
5031 realglyph = IntGetRealGlyph(&Cache);
5032 if (!realglyph)
5033 break;
5034
5035 /* Retrieve kerning distance */
5036 if (use_kerning && previous && glyph_index)
5037 {
5038 FT_Vector delta;
5039 FT_Get_Kerning(Cache.Hashed.Face, previous, glyph_index, 0, &delta);
5040 TotalWidth64 += delta.x;
5041 }
5042
5043 TotalWidth64 += realglyph->root.advance.x >> 10;
5044
5045 if (((TotalWidth64 + 32) >> 6) <= MaxExtent && NULL != Fit)
5046 {
5047 *Fit = i + 1;
5048 }
5049 if (NULL != Dx)
5050 {
5051 Dx[i] = (TotalWidth64 + 32) >> 6;
5052 }
5053
5054 previous = glyph_index;
5055 }
5056 ASSERT(FontGDI->Magic == FONTGDI_MAGIC);
5057 ascender = FontGDI->tmAscent; /* Units above baseline */
5058 descender = FontGDI->tmDescent; /* Units below baseline */
5059 IntUnLockFreeType();
5060
5061 if (bVerticalWriting)
5062 {
5063 Size->cx = ascender + descender;
5064 Size->cy = (TotalWidth64 + 32) >> 6;
5065 }
5066 else
5067 {
5068 Size->cx = (TotalWidth64 + 32) >> 6;
5069 Size->cy = ascender + descender;
5070 }
5071
5072 FontLink_Chain_Finish(&Chain);
5073
5074 return TRUE;
5075 }
5076
5077
5078 INT
5079 FASTCALL
ftGdiGetTextCharsetInfo(PDC Dc,LPFONTSIGNATURE lpSig,DWORD dwFlags)5080 ftGdiGetTextCharsetInfo(
5081 PDC Dc,
5082 LPFONTSIGNATURE lpSig,
5083 DWORD dwFlags)
5084 {
5085 PDC_ATTR pdcattr;
5086 UINT Ret = DEFAULT_CHARSET;
5087 INT i;
5088 HFONT hFont;
5089 PTEXTOBJ TextObj;
5090 PFONTGDI FontGdi;
5091 FONTSIGNATURE fs;
5092 TT_OS2 *pOS2;
5093 FT_Face Face;
5094 CHARSETINFO csi;
5095 DWORD cp, fs0;
5096 USHORT usACP, usOEM;
5097
5098 pdcattr = Dc->pdcattr;
5099 hFont = pdcattr->hlfntNew;
5100 TextObj = RealizeFontInit(hFont);
5101
5102 if (!TextObj)
5103 {
5104 EngSetLastError(ERROR_INVALID_HANDLE);
5105 return Ret;
5106 }
5107 FontGdi = ObjToGDI(TextObj->Font, FONT);
5108 Face = FontGdi->SharedFace->Face;
5109 TEXTOBJ_UnlockText(TextObj);
5110
5111 memset(&fs, 0, sizeof(FONTSIGNATURE));
5112 IntLockFreeType();
5113 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
5114 if (NULL != pOS2)
5115 {
5116 fs.fsCsb[0] = pOS2->ulCodePageRange1;
5117 fs.fsCsb[1] = pOS2->ulCodePageRange2;
5118 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
5119 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
5120 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
5121 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
5122 if (pOS2->version == 0)
5123 {
5124 FT_UInt dummy;
5125
5126 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
5127 fs.fsCsb[0] |= FS_LATIN1;
5128 else
5129 fs.fsCsb[0] |= FS_SYMBOL;
5130 }
5131 }
5132 pOS2 = NULL;
5133 IntUnLockFreeType();
5134 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
5135 if (fs.fsCsb[0] == 0)
5136 { /* Let's see if we can find any interesting cmaps */
5137 for (i = 0; i < Face->num_charmaps; i++)
5138 {
5139 switch (Face->charmaps[i]->encoding)
5140 {
5141 case FT_ENCODING_UNICODE:
5142 case FT_ENCODING_APPLE_ROMAN:
5143 fs.fsCsb[0] |= FS_LATIN1;
5144 break;
5145 case FT_ENCODING_MS_SYMBOL:
5146 fs.fsCsb[0] |= FS_SYMBOL;
5147 break;
5148 default:
5149 break;
5150 }
5151 }
5152 }
5153 if (lpSig)
5154 {
5155 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
5156 }
5157
5158 RtlGetDefaultCodePage(&usACP, &usOEM);
5159 cp = usACP;
5160
5161 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
5162 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
5163 {
5164 DPRINT("Hit 1\n");
5165 Ret = csi.ciCharset;
5166 goto Exit;
5167 }
5168
5169 for (i = 0; i < MAXTCIINDEX; i++)
5170 {
5171 fs0 = 1L << i;
5172 if (fs.fsCsb[0] & fs0)
5173 {
5174 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
5175 {
5176 // *cp = csi.ciACP;
5177 DPRINT("Hit 2\n");
5178 Ret = csi.ciCharset;
5179 goto Exit;
5180 }
5181 else
5182 DPRINT1("TCI failing on %x\n", fs0);
5183 }
5184 }
5185 Exit:
5186 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
5187 return (MAKELONG(csi.ciACP, csi.ciCharset));
5188 }
5189
5190
5191 DWORD
5192 FASTCALL
ftGetFontUnicodeRanges(PFONTGDI Font,PGLYPHSET glyphset)5193 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
5194 {
5195 DWORD size = 0;
5196 DWORD num_ranges = 0;
5197 FT_Face face = Font->SharedFace->Face;
5198
5199 if (face->charmap == NULL)
5200 {
5201 DPRINT1("FIXME: No charmap selected! This is a BUG!\n");
5202 return 0;
5203 }
5204
5205 if (face->charmap->encoding == FT_ENCODING_UNICODE)
5206 {
5207 FT_UInt glyph_code = 0;
5208 FT_ULong char_code, char_code_prev;
5209
5210 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
5211
5212 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5213 face->num_glyphs, glyph_code, char_code);
5214
5215 if (!glyph_code) return 0;
5216
5217 if (glyphset)
5218 {
5219 glyphset->ranges[0].wcLow = (USHORT)char_code;
5220 glyphset->ranges[0].cGlyphs = 0;
5221 glyphset->cGlyphsSupported = 0;
5222 }
5223
5224 num_ranges = 1;
5225 while (glyph_code)
5226 {
5227 if (char_code < char_code_prev)
5228 {
5229 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
5230 return 0;
5231 }
5232 if (char_code - char_code_prev > 1)
5233 {
5234 num_ranges++;
5235 if (glyphset)
5236 {
5237 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5238 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
5239 glyphset->cGlyphsSupported++;
5240 }
5241 }
5242 else if (glyphset)
5243 {
5244 glyphset->ranges[num_ranges - 1].cGlyphs++;
5245 glyphset->cGlyphsSupported++;
5246 }
5247 char_code_prev = char_code;
5248 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
5249 }
5250 }
5251 else
5252 DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
5253
5254 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5255 if (glyphset)
5256 {
5257 glyphset->cbThis = size;
5258 glyphset->cRanges = num_ranges;
5259 glyphset->flAccel = 0;
5260 }
5261 return size;
5262 }
5263
5264
5265 BOOL
5266 FASTCALL
ftGdiGetTextMetricsW(HDC hDC,PTMW_INTERNAL ptmwi)5267 ftGdiGetTextMetricsW(
5268 HDC hDC,
5269 PTMW_INTERNAL ptmwi)
5270 {
5271 PDC dc;
5272 PDC_ATTR pdcattr;
5273 PTEXTOBJ TextObj;
5274 PFONTGDI FontGDI;
5275 FT_Face Face;
5276 TT_OS2 *pOS2;
5277 TT_HoriHeader *pHori;
5278 FT_WinFNT_HeaderRec Win;
5279 ULONG Error;
5280 NTSTATUS Status = STATUS_SUCCESS;
5281 LOGFONTW *plf;
5282
5283 if (!ptmwi)
5284 {
5285 EngSetLastError(STATUS_INVALID_PARAMETER);
5286 return FALSE;
5287 }
5288 RtlZeroMemory(ptmwi, sizeof(TMW_INTERNAL));
5289
5290 if (!(dc = DC_LockDc(hDC)))
5291 {
5292 EngSetLastError(ERROR_INVALID_HANDLE);
5293 return FALSE;
5294 }
5295 pdcattr = dc->pdcattr;
5296 TextObj = RealizeFontInit(pdcattr->hlfntNew);
5297 if (NULL != TextObj)
5298 {
5299 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5300 FontGDI = ObjToGDI(TextObj->Font, FONT);
5301
5302 Face = FontGDI->SharedFace->Face;
5303
5304 // NOTE: GetTextMetrics simply ignores lfEscapement and XFORM.
5305 IntLockFreeType();
5306 Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
5307 FT_Set_Transform(Face, NULL, NULL);
5308
5309 IntUnLockFreeType();
5310
5311 if (0 != Error)
5312 {
5313 DPRINT1("Error in setting pixel sizes: %u\n", Error);
5314 Status = STATUS_UNSUCCESSFUL;
5315 }
5316 else
5317 {
5318 Status = STATUS_SUCCESS;
5319
5320 IntLockFreeType();
5321 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
5322 if (NULL == pOS2)
5323 {
5324 DPRINT1("Can't find OS/2 table - not TT font?\n");
5325 Status = STATUS_INTERNAL_ERROR;
5326 }
5327
5328 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
5329 if (NULL == pHori)
5330 {
5331 DPRINT1("Can't find HHEA table - not TT font?\n");
5332 Status = STATUS_INTERNAL_ERROR;
5333 }
5334
5335 Error = FT_Get_WinFNT_Header(Face, &Win);
5336
5337 if (NT_SUCCESS(Status) || !Error)
5338 {
5339 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
5340
5341 /* FIXME: Fill Diff member */
5342 }
5343
5344 IntUnLockFreeType();
5345 }
5346 TEXTOBJ_UnlockText(TextObj);
5347 }
5348 else
5349 {
5350 Status = STATUS_INVALID_HANDLE;
5351 }
5352 DC_UnlockDc(dc);
5353
5354 if (!NT_SUCCESS(Status))
5355 {
5356 SetLastNtError(Status);
5357 return FALSE;
5358 }
5359 return TRUE;
5360 }
5361
5362 DWORD
5363 FASTCALL
ftGdiGetFontData(PFONTGDI FontGdi,DWORD Table,DWORD Offset,PVOID Buffer,DWORD Size)5364 ftGdiGetFontData(
5365 PFONTGDI FontGdi,
5366 DWORD Table,
5367 DWORD Offset,
5368 PVOID Buffer,
5369 DWORD Size)
5370 {
5371 DWORD Result = GDI_ERROR;
5372 FT_Face Face = FontGdi->SharedFace->Face;
5373
5374 IntLockFreeType();
5375
5376 if (FT_IS_SFNT(Face))
5377 {
5378 if (Table)
5379 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
5380 (Table << 8 & 0xFF0000);
5381
5382 if (!Buffer) Size = 0;
5383
5384 if (Buffer && Size)
5385 {
5386 FT_Error Error;
5387 FT_ULong Needed = 0;
5388
5389 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
5390
5391 if ( !Error && Needed < Size) Size = Needed;
5392 }
5393 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
5394 Result = Size;
5395 }
5396
5397 IntUnLockFreeType();
5398
5399 return Result;
5400 }
5401
5402 #define GOT_PENALTY(name, value) Penalty += (value)
5403
5404 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
5405 static UINT
GetFontPenalty(const LOGFONTW * LogFont,const OUTLINETEXTMETRICW * Otm,const char * style_name)5406 GetFontPenalty(const LOGFONTW * LogFont,
5407 const OUTLINETEXTMETRICW * Otm,
5408 const char * style_name)
5409 {
5410 ULONG Penalty = 0;
5411 BYTE Byte;
5412 LONG Long;
5413 BOOL fNeedScaling = FALSE;
5414 const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
5415 const TEXTMETRICW * TM = &Otm->otmTextMetrics;
5416 WCHAR* ActualNameW;
5417
5418 ASSERT(Otm);
5419 ASSERT(LogFont);
5420
5421 /* FIXME: IntSizeSynth Penalty 20 */
5422 /* FIXME: SmallPenalty Penalty 1 */
5423 /* FIXME: FaceNameSubst Penalty 500 */
5424
5425 Byte = LogFont->lfCharSet;
5426
5427 if (Byte != TM->tmCharSet)
5428 {
5429 if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
5430 {
5431 /* CharSet Penalty 65000 */
5432 /* Requested charset does not match the candidate's. */
5433 GOT_PENALTY("CharSet", 65000);
5434 }
5435 else
5436 {
5437 if (UserCharSet != TM->tmCharSet)
5438 {
5439 /* UNDOCUMENTED: Not user language */
5440 GOT_PENALTY("UNDOCUMENTED:NotUserLanguage", 100);
5441
5442 if (ANSI_CHARSET != TM->tmCharSet)
5443 {
5444 /* UNDOCUMENTED: Not ANSI charset */
5445 GOT_PENALTY("UNDOCUMENTED:NotAnsiCharSet", 100);
5446 }
5447 }
5448 }
5449 }
5450
5451 Byte = LogFont->lfOutPrecision;
5452 switch (Byte)
5453 {
5454 case OUT_DEFAULT_PRECIS:
5455 /* nothing to do */
5456 break;
5457 case OUT_DEVICE_PRECIS:
5458 if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
5459 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
5460 {
5461 /* OutputPrecision Penalty 19000 */
5462 /* Requested OUT_STROKE_PRECIS, but the device can't do it
5463 or the candidate is not a vector font. */
5464 GOT_PENALTY("OutputPrecision", 19000);
5465 }
5466 break;
5467 default:
5468 if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
5469 {
5470 /* OutputPrecision Penalty 19000 */
5471 /* Or OUT_STROKE_PRECIS not requested, and the candidate
5472 is a vector font that requires GDI support. */
5473 GOT_PENALTY("OutputPrecision", 19000);
5474 }
5475 break;
5476 }
5477
5478 Byte = (LogFont->lfPitchAndFamily & 0x0F);
5479 if (Byte == DEFAULT_PITCH)
5480 Byte = VARIABLE_PITCH;
5481 if (Byte == FIXED_PITCH)
5482 {
5483 if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
5484 {
5485 /* FixedPitch Penalty 15000 */
5486 /* Requested a fixed pitch font, but the candidate is a
5487 variable pitch font. */
5488 GOT_PENALTY("FixedPitch", 15000);
5489 }
5490 }
5491 if (Byte == VARIABLE_PITCH)
5492 {
5493 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
5494 {
5495 /* PitchVariable Penalty 350 */
5496 /* Requested a variable pitch font, but the candidate is not a
5497 variable pitch font. */
5498 GOT_PENALTY("PitchVariable", 350);
5499 }
5500 }
5501
5502 Byte = (LogFont->lfPitchAndFamily & 0x0F);
5503 if (Byte == DEFAULT_PITCH)
5504 {
5505 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
5506 {
5507 /* DefaultPitchFixed Penalty 1 */
5508 /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
5509 GOT_PENALTY("DefaultPitchFixed", 1);
5510 }
5511 }
5512
5513 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
5514
5515 if (LogFont->lfFaceName[0] != UNICODE_NULL)
5516 {
5517 BOOL Found = FALSE;
5518
5519 /* localized family name */
5520 if (!Found)
5521 {
5522 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
5523 }
5524 /* localized full name */
5525 if (!Found)
5526 {
5527 ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
5528 Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
5529 }
5530 if (!Found)
5531 {
5532 /* FaceName Penalty 10000 */
5533 /* Requested a face name, but the candidate's face name
5534 does not match. */
5535 GOT_PENALTY("FaceName", 10000);
5536 }
5537 }
5538
5539 Byte = (LogFont->lfPitchAndFamily & 0xF0);
5540 if (Byte != FF_DONTCARE)
5541 {
5542 if (Byte != (TM->tmPitchAndFamily & 0xF0))
5543 {
5544 /* Family Penalty 9000 */
5545 /* Requested a family, but the candidate's family is different. */
5546 GOT_PENALTY("Family", 9000);
5547 }
5548 }
5549
5550 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
5551 {
5552 /* FamilyUnknown Penalty 8000 */
5553 /* Requested a family, but the candidate has no family. */
5554 GOT_PENALTY("FamilyUnknown", 8000);
5555 }
5556
5557 /* Is the candidate a non-vector font? */
5558 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
5559 {
5560 /* Is lfHeight specified? */
5561 if (LogFont->lfHeight != 0)
5562 {
5563 if (labs(LogFont->lfHeight) < TM->tmHeight)
5564 {
5565 /* HeightBigger Penalty 600 */
5566 /* The candidate is a nonvector font and is bigger than the
5567 requested height. */
5568 GOT_PENALTY("HeightBigger", 600);
5569 /* HeightBiggerDifference Penalty 150 */
5570 /* The candidate is a raster font and is larger than the
5571 requested height. Penalty * height difference */
5572 GOT_PENALTY("HeightBiggerDifference", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)));
5573
5574 fNeedScaling = TRUE;
5575 }
5576 if (TM->tmHeight < labs(LogFont->lfHeight))
5577 {
5578 /* HeightSmaller Penalty 150 */
5579 /* The candidate is a raster font and is smaller than the
5580 requested height. Penalty * height difference */
5581 GOT_PENALTY("HeightSmaller", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)));
5582
5583 fNeedScaling = TRUE;
5584 }
5585 }
5586 }
5587
5588 switch (LogFont->lfPitchAndFamily & 0xF0)
5589 {
5590 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
5591 switch (TM->tmPitchAndFamily & 0xF0)
5592 {
5593 case FF_DECORATIVE: case FF_SCRIPT:
5594 /* FamilyUnlikely Penalty 50 */
5595 /* Requested a roman/modern/swiss family, but the
5596 candidate is decorative/script. */
5597 GOT_PENALTY("FamilyUnlikely", 50);
5598 break;
5599 default:
5600 break;
5601 }
5602 break;
5603 case FF_DECORATIVE: case FF_SCRIPT:
5604 switch (TM->tmPitchAndFamily & 0xF0)
5605 {
5606 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
5607 /* FamilyUnlikely Penalty 50 */
5608 /* Or requested decorative/script, and the candidate is
5609 roman/modern/swiss. */
5610 GOT_PENALTY("FamilyUnlikely", 50);
5611 break;
5612 default:
5613 break;
5614 }
5615 default:
5616 break;
5617 }
5618
5619 if (LogFont->lfWidth != 0)
5620 {
5621 if (LogFont->lfWidth != TM->tmAveCharWidth)
5622 {
5623 /* Width Penalty 50 */
5624 /* Requested a nonzero width, but the candidate's width
5625 doesn't match. Penalty * width difference */
5626 GOT_PENALTY("Width", 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth));
5627
5628 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
5629 fNeedScaling = TRUE;
5630 }
5631 }
5632
5633 if (fNeedScaling)
5634 {
5635 /* SizeSynth Penalty 50 */
5636 /* The candidate is a raster font that needs scaling by GDI. */
5637 GOT_PENALTY("SizeSynth", 50);
5638 }
5639
5640 if (!LogFont->lfItalic && TM->tmItalic)
5641 {
5642 /* Italic Penalty 4 */
5643 /* Requested font and candidate font do not agree on italic status,
5644 and the desired result cannot be simulated. */
5645 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
5646 GOT_PENALTY("Italic", 40);
5647 }
5648 else if (LogFont->lfItalic && !TM->tmItalic)
5649 {
5650 /* ItalicSim Penalty 1 */
5651 /* Requested italic font but the candidate is not italic,
5652 although italics can be simulated. */
5653 GOT_PENALTY("ItalicSim", 1);
5654 }
5655
5656 if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
5657 {
5658 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
5659 {
5660 /* NotTrueType Penalty 4 */
5661 /* Requested OUT_TT_PRECIS, but the candidate is not a
5662 TrueType font. */
5663 GOT_PENALTY("NotTrueType", 4);
5664 }
5665 }
5666
5667 Long = LogFont->lfWeight;
5668 if (LogFont->lfWeight == FW_DONTCARE)
5669 Long = FW_NORMAL;
5670 if (Long != TM->tmWeight)
5671 {
5672 /* Weight Penalty 3 */
5673 /* The candidate's weight does not match the requested weight.
5674 Penalty * (weight difference/10) */
5675 GOT_PENALTY("Weight", 3 * (labs(Long - TM->tmWeight) / 10));
5676 }
5677
5678 if (!LogFont->lfUnderline && TM->tmUnderlined)
5679 {
5680 /* Underline Penalty 3 */
5681 /* Requested font has no underline, but the candidate is
5682 underlined. */
5683 GOT_PENALTY("Underline", 3);
5684 }
5685
5686 if (!LogFont->lfStrikeOut && TM->tmStruckOut)
5687 {
5688 /* StrikeOut Penalty 3 */
5689 /* Requested font has no strike-out, but the candidate is
5690 struck out. */
5691 GOT_PENALTY("StrikeOut", 3);
5692 }
5693
5694 /* Is the candidate a non-vector font? */
5695 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
5696 {
5697 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
5698 {
5699 /* VectorHeightSmaller Penalty 2 */
5700 /* Candidate is a vector font that is smaller than the
5701 requested height. Penalty * height difference */
5702 GOT_PENALTY("VectorHeightSmaller", 2 * labs(TM->tmHeight - LogFont->lfHeight));
5703 }
5704 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
5705 {
5706 /* VectorHeightBigger Penalty 1 */
5707 /* Candidate is a vector font that is bigger than the
5708 requested height. Penalty * height difference */
5709 GOT_PENALTY("VectorHeightBigger", 1 * labs(TM->tmHeight - LogFont->lfHeight));
5710 }
5711 }
5712
5713 if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
5714 {
5715 /* DeviceFavor Penalty 2 */
5716 /* Extra penalty for all nondevice fonts. */
5717 GOT_PENALTY("DeviceFavor", 2);
5718 }
5719
5720 if (TM->tmAveCharWidth >= 5 && TM->tmHeight >= 5)
5721 {
5722 if (TM->tmAveCharWidth / TM->tmHeight >= 3)
5723 {
5724 /* Aspect Penalty 30 */
5725 /* The aspect rate is >= 3. It seems like a bad font. */
5726 GOT_PENALTY("Aspect", ((TM->tmAveCharWidth / TM->tmHeight) - 2) * 30);
5727 }
5728 else if (TM->tmHeight / TM->tmAveCharWidth >= 3)
5729 {
5730 /* Aspect Penalty 30 */
5731 /* The aspect rate is >= 3. It seems like a bad font. */
5732 GOT_PENALTY("Aspect", ((TM->tmHeight / TM->tmAveCharWidth) - 2) * 30);
5733 }
5734 }
5735
5736 if (Penalty < 200)
5737 {
5738 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
5739 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
5740 "tmCharSet:%d, tmWeight:%ld\n",
5741 Penalty, LogFont->lfFaceName, ActualNameW,
5742 LogFont->lfCharSet, LogFont->lfWeight,
5743 TM->tmCharSet, TM->tmWeight);
5744 }
5745
5746 return Penalty; /* success */
5747 }
5748
5749 #undef GOT_PENALTY
5750
5751 static __inline VOID
FindBestFontFromList(FONTOBJ ** FontObj,ULONG * MatchPenalty,const LOGFONTW * LogFont,const PLIST_ENTRY Head)5752 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
5753 const LOGFONTW *LogFont,
5754 const PLIST_ENTRY Head)
5755 {
5756 ULONG Penalty;
5757 PLIST_ENTRY Entry;
5758 PFONT_ENTRY CurrentEntry;
5759 FONTGDI *FontGDI;
5760 OUTLINETEXTMETRICW *Otm = NULL;
5761 UINT OtmSize, OldOtmSize = 0;
5762 FT_Face Face;
5763
5764 ASSERT(FontObj);
5765 ASSERT(MatchPenalty);
5766 ASSERT(LogFont);
5767 ASSERT(Head);
5768
5769 /* Start with a pretty big buffer */
5770 OldOtmSize = 0x200;
5771 Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
5772
5773 /* get the FontObj of lowest penalty */
5774 for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
5775 {
5776 CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
5777
5778 FontGDI = CurrentEntry->Font;
5779 ASSERT(FontGDI);
5780 Face = FontGDI->SharedFace->Face;
5781
5782 /* get text metrics */
5783 ASSERT_FREETYPE_LOCK_HELD();
5784 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL, TRUE);
5785 if (OtmSize > OldOtmSize)
5786 {
5787 if (Otm)
5788 ExFreePoolWithTag(Otm, GDITAG_TEXT);
5789 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
5790 }
5791
5792 /* update FontObj if lowest penalty */
5793 if (Otm)
5794 {
5795 ASSERT_FREETYPE_LOCK_HELD();
5796 IntRequestFontSize(NULL, FontGDI, LogFont->lfWidth, LogFont->lfHeight);
5797
5798 ASSERT_FREETYPE_LOCK_HELD();
5799 OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm, TRUE);
5800 if (!OtmSize)
5801 continue;
5802
5803 OldOtmSize = OtmSize;
5804
5805 Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
5806 if (*MatchPenalty == MAXULONG || Penalty < *MatchPenalty)
5807 {
5808 *FontObj = GDIToObj(FontGDI, FONT);
5809 *MatchPenalty = Penalty;
5810 }
5811 }
5812 }
5813
5814 if (Otm)
5815 ExFreePoolWithTag(Otm, GDITAG_TEXT);
5816 }
5817
5818 static
5819 VOID
5820 FASTCALL
IntFontType(PFONTGDI Font)5821 IntFontType(PFONTGDI Font)
5822 {
5823 PS_FontInfoRec psfInfo;
5824 FT_ULong tmp_size = 0;
5825 FT_Face Face = Font->SharedFace->Face;
5826
5827 ASSERT_FREETYPE_LOCK_NOT_HELD();
5828 IntLockFreeType();
5829
5830 if (FT_HAS_MULTIPLE_MASTERS(Face))
5831 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
5832 if (FT_HAS_VERTICAL(Face))
5833 Font->FontObj.flFontType |= FO_VERT_FACE;
5834 if (!FT_IS_SCALABLE(Face))
5835 Font->FontObj.flFontType |= FO_TYPE_RASTER;
5836 if (FT_IS_SFNT(Face))
5837 {
5838 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
5839 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
5840 Font->FontObj.flFontType |= FO_POSTSCRIPT;
5841 }
5842 if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
5843 {
5844 Font->FontObj.flFontType |= FO_POSTSCRIPT;
5845 }
5846 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
5847 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
5848 {
5849 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
5850 }
5851
5852 IntUnLockFreeType();
5853 }
5854
5855 static BOOL
MatchFontName(PSHARED_FACE SharedFace,PUNICODE_STRING Name1,FT_UShort NameID,FT_UShort LangID)5856 MatchFontName(PSHARED_FACE SharedFace, PUNICODE_STRING Name1, FT_UShort NameID, FT_UShort LangID)
5857 {
5858 NTSTATUS Status;
5859 UNICODE_STRING Name2;
5860
5861 RtlInitUnicodeString(&Name2, NULL);
5862 Status = IntGetFontLocalizedName(&Name2, SharedFace, NameID, LangID);
5863
5864 if (NT_SUCCESS(Status))
5865 {
5866 if (RtlCompareUnicodeString(Name1, &Name2, TRUE) == 0)
5867 {
5868 RtlFreeUnicodeString(&Name2);
5869 return TRUE;
5870 }
5871
5872 RtlFreeUnicodeString(&Name2);
5873 }
5874
5875 return FALSE;
5876 }
5877
5878 static BOOL
MatchFontNames(PSHARED_FACE SharedFace,LPCWSTR lfFaceName)5879 MatchFontNames(PSHARED_FACE SharedFace, LPCWSTR lfFaceName)
5880 {
5881 UNICODE_STRING Name1;
5882
5883 if (lfFaceName[0] == UNICODE_NULL)
5884 return FALSE;
5885
5886 RtlInitUnicodeString(&Name1, lfFaceName);
5887
5888 if (MatchFontName(SharedFace, &Name1, TT_NAME_ID_FONT_FAMILY, LANG_ENGLISH) ||
5889 MatchFontName(SharedFace, &Name1, TT_NAME_ID_FULL_NAME, LANG_ENGLISH))
5890 {
5891 return TRUE;
5892 }
5893 if (PRIMARYLANGID(gusLanguageID) != LANG_ENGLISH)
5894 {
5895 if (MatchFontName(SharedFace, &Name1, TT_NAME_ID_FONT_FAMILY, gusLanguageID) ||
5896 MatchFontName(SharedFace, &Name1, TT_NAME_ID_FULL_NAME, gusLanguageID))
5897 {
5898 return TRUE;
5899 }
5900 }
5901 return FALSE;
5902 }
5903
5904 NTSTATUS
5905 FASTCALL
TextIntRealizeFont(HFONT FontHandle,PTEXTOBJ pTextObj)5906 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
5907 {
5908 NTSTATUS Status = STATUS_SUCCESS;
5909 PTEXTOBJ TextObj;
5910 PPROCESSINFO Win32Process;
5911 ULONG MatchPenalty;
5912 LOGFONTW *pLogFont;
5913 LOGFONTW SubstitutedLogFont;
5914
5915 if (!pTextObj)
5916 {
5917 TextObj = TEXTOBJ_LockText(FontHandle);
5918 if (NULL == TextObj)
5919 {
5920 return STATUS_INVALID_HANDLE;
5921 }
5922
5923 if (TextObj->fl & TEXTOBJECT_INIT)
5924 {
5925 TEXTOBJ_UnlockText(TextObj);
5926 return STATUS_SUCCESS;
5927 }
5928 }
5929 else
5930 {
5931 TextObj = pTextObj;
5932 }
5933
5934 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5935
5936 /* substitute */
5937 SubstitutedLogFont = *pLogFont;
5938 DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
5939 SubstituteFontRecurse(&SubstitutedLogFont);
5940 DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
5941
5942 MatchPenalty = 0xFFFFFFFF;
5943 TextObj->Font = NULL;
5944
5945 Win32Process = PsGetCurrentProcessWin32Process();
5946
5947 /* Search private fonts */
5948 IntLockFreeType();
5949 IntLockProcessPrivateFonts(Win32Process);
5950 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
5951 &Win32Process->PrivateFontListHead);
5952 IntUnLockProcessPrivateFonts(Win32Process);
5953
5954 /* Search system fonts */
5955 FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
5956 &g_FontListHead);
5957 IntUnLockFreeType();
5958
5959 if (NULL == TextObj->Font)
5960 {
5961 DPRINT1("Request font %S not found, no fonts loaded at all\n",
5962 pLogFont->lfFaceName);
5963 Status = STATUS_NOT_FOUND;
5964 }
5965 else
5966 {
5967 UNICODE_STRING Name;
5968 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
5969 PSHARED_FACE SharedFace = FontGdi->SharedFace;
5970
5971 TextObj->TextFace[0] = UNICODE_NULL;
5972 IntLockFreeType();
5973 if (MatchFontNames(SharedFace, SubstitutedLogFont.lfFaceName))
5974 {
5975 IntUnLockFreeType();
5976 RtlStringCchCopyW(TextObj->TextFace, _countof(TextObj->TextFace), pLogFont->lfFaceName);
5977 }
5978 else
5979 {
5980 RtlInitUnicodeString(&Name, NULL);
5981 Status = IntGetFontLocalizedName(&Name, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
5982 IntUnLockFreeType();
5983 if (NT_SUCCESS(Status))
5984 {
5985 /* truncated copy */
5986 IntUnicodeStringToBuffer(TextObj->TextFace, sizeof(TextObj->TextFace), &Name);
5987 RtlFreeUnicodeString(&Name);
5988 }
5989 }
5990
5991 // Need hdev, when freetype is loaded need to create DEVOBJ for
5992 // Consumer and Producer.
5993 TextObj->Font->iUniq = 1; // Now it can be cached.
5994 IntFontType(FontGdi);
5995 FontGdi->flType = TextObj->Font->flFontType;
5996 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
5997 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
5998 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
5999 if (pLogFont->lfWeight != FW_DONTCARE)
6000 FontGdi->RequestWeight = pLogFont->lfWeight;
6001 else
6002 FontGdi->RequestWeight = FW_NORMAL;
6003
6004 TextObj->fl |= TEXTOBJECT_INIT;
6005 Status = STATUS_SUCCESS;
6006 }
6007
6008 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
6009
6010 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
6011
6012 return Status;
6013 }
6014
6015 static
6016 BOOL
6017 FASTCALL
IntGetFullFileName(POBJECT_NAME_INFORMATION NameInfo,ULONG Size,PUNICODE_STRING FileName)6018 IntGetFullFileName(
6019 POBJECT_NAME_INFORMATION NameInfo,
6020 ULONG Size,
6021 PUNICODE_STRING FileName)
6022 {
6023 NTSTATUS Status;
6024 OBJECT_ATTRIBUTES ObjectAttributes;
6025 HANDLE hFile;
6026 IO_STATUS_BLOCK IoStatusBlock;
6027 ULONG Desired;
6028
6029 InitializeObjectAttributes(&ObjectAttributes,
6030 FileName,
6031 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
6032 NULL,
6033 NULL);
6034
6035 Status = ZwOpenFile(
6036 &hFile,
6037 0, // FILE_READ_ATTRIBUTES,
6038 &ObjectAttributes,
6039 &IoStatusBlock,
6040 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
6041 0);
6042
6043 if (!NT_SUCCESS(Status))
6044 {
6045 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
6046 return FALSE;
6047 }
6048
6049 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
6050 ZwClose(hFile);
6051 if (!NT_SUCCESS(Status))
6052 {
6053 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
6054 return FALSE;
6055 }
6056
6057 return TRUE;
6058 }
6059
6060 static BOOL
EqualFamilyInfo(const FONTFAMILYINFO * pInfo1,const FONTFAMILYINFO * pInfo2)6061 EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2)
6062 {
6063 const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
6064 const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
6065 const LOGFONTW *plf1 = &pLog1->elfLogFont;
6066 const LOGFONTW *plf2 = &pLog2->elfLogFont;
6067
6068 if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0)
6069 {
6070 return FALSE;
6071 }
6072
6073 if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0)
6074 {
6075 return FALSE;
6076 }
6077
6078 return TRUE;
6079 }
6080
6081 static VOID
IntAddNameFromFamInfo(LPWSTR psz,FONTFAMILYINFO * FamInfo)6082 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
6083 {
6084 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
6085 if (FamInfo->EnumLogFontEx.elfStyle[0] &&
6086 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
6087 {
6088 wcscat(psz, L" ");
6089 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
6090 }
6091 }
6092
6093 BOOL
6094 FASTCALL
IntGdiGetFontResourceInfo(PUNICODE_STRING FileName,PVOID pBuffer,DWORD * pdwBytes,DWORD dwType)6095 IntGdiGetFontResourceInfo(
6096 PUNICODE_STRING FileName,
6097 PVOID pBuffer,
6098 DWORD *pdwBytes,
6099 DWORD dwType)
6100 {
6101 UNICODE_STRING EntryFileName;
6102 POBJECT_NAME_INFORMATION NameInfo1 = NULL, NameInfo2 = NULL;
6103 PLIST_ENTRY ListEntry;
6104 PFONT_ENTRY FontEntry;
6105 ULONG Size, i, Count;
6106 LPBYTE pbBuffer;
6107 BOOL IsEqual;
6108 FONTFAMILYINFO *FamInfo;
6109 const ULONG MaxFamInfo = 64;
6110 const ULONG MAX_FAM_INFO_BYTES = sizeof(FONTFAMILYINFO) * MaxFamInfo;
6111 BOOL bSuccess;
6112 const ULONG NAMEINFO_SIZE = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
6113
6114 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
6115
6116 do
6117 {
6118 /* Create buffer for full path name */
6119 NameInfo1 = ExAllocatePoolWithTag(PagedPool, NAMEINFO_SIZE, TAG_FINF);
6120 if (!NameInfo1)
6121 break;
6122
6123 /* Get the full path name */
6124 if (!IntGetFullFileName(NameInfo1, NAMEINFO_SIZE, FileName))
6125 break;
6126
6127 /* Create a buffer for the entries' names */
6128 NameInfo2 = ExAllocatePoolWithTag(PagedPool, NAMEINFO_SIZE, TAG_FINF);
6129 if (!NameInfo2)
6130 break;
6131
6132 FamInfo = ExAllocatePoolWithTag(PagedPool, MAX_FAM_INFO_BYTES, TAG_FINF);
6133 } while (0);
6134
6135 if (!NameInfo1 || !NameInfo2 || !FamInfo)
6136 {
6137 if (NameInfo2)
6138 ExFreePoolWithTag(NameInfo2, TAG_FINF);
6139
6140 if (NameInfo1)
6141 ExFreePoolWithTag(NameInfo1, TAG_FINF);
6142
6143 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6144 return FALSE;
6145 }
6146
6147 Count = 0;
6148
6149 /* Try to find the pathname in the global font list */
6150 IntLockFreeType();
6151 for (ListEntry = g_FontListHead.Flink; ListEntry != &g_FontListHead;
6152 ListEntry = ListEntry->Flink)
6153 {
6154 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
6155 if (FontEntry->Font->Filename == NULL)
6156 continue;
6157
6158 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
6159 if (!IntGetFullFileName(NameInfo2, NAMEINFO_SIZE, &EntryFileName))
6160 continue;
6161
6162 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
6163 continue;
6164
6165 IsEqual = FALSE;
6166 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
6167 NULL, FontEntry->Font);
6168 for (i = 0; i < Count; ++i)
6169 {
6170 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
6171 {
6172 IsEqual = TRUE;
6173 break;
6174 }
6175 }
6176 if (!IsEqual)
6177 {
6178 /* Found */
6179 ++Count;
6180 if (Count >= MaxFamInfo)
6181 break;
6182 }
6183 }
6184 IntUnLockFreeType();
6185
6186 /* Free the buffers */
6187 ExFreePoolWithTag(NameInfo1, TAG_FINF);
6188 ExFreePoolWithTag(NameInfo2, TAG_FINF);
6189
6190 if (Count == 0 && dwType != 5)
6191 {
6192 /* Font could not be found in system table
6193 dwType == 5 will still handle this */
6194 ExFreePoolWithTag(FamInfo, TAG_FINF);
6195 return FALSE;
6196 }
6197
6198 bSuccess = FALSE;
6199 switch (dwType)
6200 {
6201 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
6202 Size = sizeof(DWORD);
6203 if (*pdwBytes == 0)
6204 {
6205 *pdwBytes = Size;
6206 bSuccess = TRUE;
6207 }
6208 else if (pBuffer)
6209 {
6210 if (*pdwBytes >= Size)
6211 {
6212 *(DWORD*)pBuffer = Count;
6213 }
6214 *pdwBytes = Size;
6215 bSuccess = TRUE;
6216 }
6217 break;
6218
6219 case 1: /* copy the font title */
6220 /* calculate the required size */
6221 Size = 0;
6222 for (i = 0; i < Count; ++i)
6223 {
6224 if (i > 0)
6225 Size += 3; /* " & " */
6226 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
6227 if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
6228 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
6229 {
6230 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
6231 }
6232 }
6233 Size += 2; /* "\0\0" */
6234 Size *= sizeof(WCHAR);
6235
6236 if (*pdwBytes == 0)
6237 {
6238 *pdwBytes = Size;
6239 bSuccess = TRUE;
6240 }
6241 else if (pBuffer)
6242 {
6243 if (*pdwBytes >= Size)
6244 {
6245 /* store font title to buffer */
6246 WCHAR *psz = pBuffer;
6247 *psz = 0;
6248 for (i = 0; i < Count; ++i)
6249 {
6250 if (i > 0)
6251 wcscat(psz, L" & ");
6252 IntAddNameFromFamInfo(psz, &FamInfo[i]);
6253 }
6254 psz[wcslen(psz) + 1] = UNICODE_NULL;
6255 *pdwBytes = Size;
6256 bSuccess = TRUE;
6257 }
6258 else
6259 {
6260 *pdwBytes = 1024; /* this is confirmed value */
6261 }
6262 }
6263 break;
6264
6265 case 2: /* Copy an array of LOGFONTW */
6266 Size = Count * sizeof(LOGFONTW);
6267 if (*pdwBytes == 0)
6268 {
6269 *pdwBytes = Size;
6270 bSuccess = TRUE;
6271 }
6272 else if (pBuffer)
6273 {
6274 if (*pdwBytes >= Size)
6275 {
6276 pbBuffer = (LPBYTE)pBuffer;
6277 for (i = 0; i < Count; ++i)
6278 {
6279 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
6280 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
6281 pbBuffer += sizeof(LOGFONTW);
6282 }
6283 }
6284 *pdwBytes = Size;
6285 bSuccess = TRUE;
6286 }
6287 else
6288 {
6289 *pdwBytes = 1024; /* this is confirmed value */
6290 }
6291 break;
6292
6293 case 3:
6294 Size = sizeof(DWORD);
6295 if (*pdwBytes == 0)
6296 {
6297 *pdwBytes = Size;
6298 bSuccess = TRUE;
6299 }
6300 else if (pBuffer)
6301 {
6302 if (*pdwBytes >= Size)
6303 {
6304 /* FIXME: What exactly is copied here? */
6305 *(DWORD*)pBuffer = 1;
6306 }
6307 *pdwBytes = Size;
6308 bSuccess = TRUE;
6309 }
6310 break;
6311
6312 case 4: /* full file path */
6313 if (FileName->Length >= 4 * sizeof(WCHAR))
6314 {
6315 /* The beginning of FileName is \??\ */
6316 LPWSTR pch = FileName->Buffer + 4;
6317 DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
6318
6319 Size = Length + sizeof(WCHAR);
6320 if (*pdwBytes == 0)
6321 {
6322 *pdwBytes = Size;
6323 bSuccess = TRUE;
6324 }
6325 else if (pBuffer)
6326 {
6327 if (*pdwBytes >= Size)
6328 {
6329 RtlCopyMemory(pBuffer, pch, Size);
6330 }
6331 *pdwBytes = Size;
6332 bSuccess = TRUE;
6333 }
6334 }
6335 break;
6336
6337 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
6338 Size = sizeof(BOOL);
6339 if (*pdwBytes == 0)
6340 {
6341 *pdwBytes = Size;
6342 bSuccess = TRUE;
6343 }
6344 else if (pBuffer)
6345 {
6346 if (*pdwBytes >= Size)
6347 {
6348 *(BOOL*)pBuffer = Count == 0;
6349 }
6350 *pdwBytes = Size;
6351 bSuccess = TRUE;
6352 }
6353 break;
6354 }
6355 ExFreePoolWithTag(FamInfo, TAG_FINF);
6356
6357 return bSuccess;
6358 }
6359
6360
6361 BOOL
6362 FASTCALL
ftGdiRealizationInfo(PFONTGDI Font,PREALIZATION_INFO Info)6363 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
6364 {
6365 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
6366 Info->iTechnology = RI_TECH_BITMAP;
6367 else
6368 {
6369 if (FT_IS_SCALABLE(Font->SharedFace->Face))
6370 Info->iTechnology = RI_TECH_SCALABLE;
6371 else
6372 Info->iTechnology = RI_TECH_FIXED;
6373 }
6374 Info->iUniq = Font->FontObj.iUniq;
6375 Info->dwUnknown = -1;
6376 return TRUE;
6377 }
6378
6379
6380 DWORD
6381 FASTCALL
ftGdiGetKerningPairs(PFONTGDI Font,DWORD cPairs,LPKERNINGPAIR pKerningPair)6382 ftGdiGetKerningPairs( PFONTGDI Font,
6383 DWORD cPairs,
6384 LPKERNINGPAIR pKerningPair)
6385 {
6386 DWORD Count = 0;
6387 INT i = 0;
6388 FT_Face face = Font->SharedFace->Face;
6389
6390 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
6391 {
6392 FT_UInt previous_index = 0, glyph_index = 0;
6393 FT_ULong char_code, char_previous;
6394 FT_Vector delta;
6395
6396 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
6397
6398 IntLockFreeType();
6399
6400 while (glyph_index)
6401 {
6402 if (previous_index && glyph_index)
6403 {
6404 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
6405
6406 if (pKerningPair && cPairs)
6407 {
6408 pKerningPair[i].wFirst = char_previous;
6409 pKerningPair[i].wSecond = char_code;
6410 pKerningPair[i].iKernAmount = delta.x;
6411 i++;
6412 if (i == cPairs) break;
6413 }
6414 Count++;
6415 }
6416 previous_index = glyph_index;
6417 char_previous = char_code;
6418 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
6419 }
6420 IntUnLockFreeType();
6421 }
6422 return Count;
6423 }
6424
6425
6426 ///////////////////////////////////////////////////////////////////////////
6427 //
6428 // Functions needing sorting.
6429 //
6430 ///////////////////////////////////////////////////////////////////////////
6431
6432 LONG FASTCALL
IntGetFontFamilyInfo(HDC Dc,const LOGFONTW * SafeLogFont,PFONTFAMILYINFO SafeInfo,LONG InfoCount)6433 IntGetFontFamilyInfo(HDC Dc,
6434 const LOGFONTW *SafeLogFont,
6435 PFONTFAMILYINFO SafeInfo,
6436 LONG InfoCount)
6437 {
6438 LONG AvailCount = 0;
6439 PPROCESSINFO Win32Process;
6440
6441 /* Enumerate font families in the global list */
6442 IntLockFreeType();
6443 if (!GetFontFamilyInfoForList(SafeLogFont, SafeInfo, NULL, &AvailCount,
6444 InfoCount, &g_FontListHead))
6445 {
6446 IntUnLockFreeType();
6447 return -1;
6448 }
6449
6450 /* Enumerate font families in the process local list */
6451 Win32Process = PsGetCurrentProcessWin32Process();
6452 IntLockProcessPrivateFonts(Win32Process);
6453 if (!GetFontFamilyInfoForList(SafeLogFont, SafeInfo, NULL, &AvailCount, InfoCount,
6454 &Win32Process->PrivateFontListHead))
6455 {
6456 IntUnLockProcessPrivateFonts(Win32Process);
6457 IntUnLockFreeType();
6458 return -1;
6459 }
6460 IntUnLockProcessPrivateFonts(Win32Process);
6461 IntUnLockFreeType();
6462
6463 /* Enumerate font families in the registry */
6464 if (!GetFontFamilyInfoForSubstitutes(SafeLogFont, SafeInfo, &AvailCount, InfoCount))
6465 {
6466 return -1;
6467 }
6468
6469 return AvailCount;
6470 }
6471
6472 LONG NTAPI
NtGdiGetFontFamilyInfo(HDC Dc,const LOGFONTW * UnsafeLogFont,PFONTFAMILYINFO UnsafeInfo,LPLONG UnsafeInfoCount)6473 NtGdiGetFontFamilyInfo(HDC Dc,
6474 const LOGFONTW *UnsafeLogFont,
6475 PFONTFAMILYINFO UnsafeInfo,
6476 LPLONG UnsafeInfoCount)
6477 {
6478 NTSTATUS Status;
6479 LOGFONTW LogFont;
6480 PFONTFAMILYINFO Info;
6481 LONG GotCount, AvailCount, SafeInfoCount;
6482 ULONG DataSize;
6483
6484 if (UnsafeLogFont == NULL || UnsafeInfo == NULL || UnsafeInfoCount == NULL)
6485 {
6486 EngSetLastError(ERROR_INVALID_PARAMETER);
6487 return -1;
6488 }
6489
6490 Status = MmCopyFromCaller(&SafeInfoCount, UnsafeInfoCount, sizeof(SafeInfoCount));
6491 if (!NT_SUCCESS(Status))
6492 {
6493 EngSetLastError(ERROR_INVALID_PARAMETER);
6494 return -1;
6495 }
6496 GotCount = 0;
6497 Status = MmCopyToCaller(UnsafeInfoCount, &GotCount, sizeof(*UnsafeInfoCount));
6498 if (!NT_SUCCESS(Status))
6499 {
6500 EngSetLastError(ERROR_INVALID_PARAMETER);
6501 return -1;
6502 }
6503 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
6504 if (!NT_SUCCESS(Status))
6505 {
6506 EngSetLastError(ERROR_INVALID_PARAMETER);
6507 return -1;
6508 }
6509 if (SafeInfoCount <= 0)
6510 {
6511 EngSetLastError(ERROR_INVALID_PARAMETER);
6512 return -1;
6513 }
6514
6515 /* Allocate space for a safe copy */
6516 Status = RtlULongMult(SafeInfoCount, sizeof(FONTFAMILYINFO), &DataSize);
6517 if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
6518 {
6519 DPRINT1("Overflowed.\n");
6520 EngSetLastError(ERROR_INVALID_PARAMETER);
6521 return -1;
6522 }
6523 Info = ExAllocatePoolWithTag(PagedPool, DataSize, GDITAG_TEXT);
6524 if (Info == NULL)
6525 {
6526 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6527 return -1;
6528 }
6529
6530 /* Retrieve the information */
6531 AvailCount = IntGetFontFamilyInfo(Dc, &LogFont, Info, SafeInfoCount);
6532 GotCount = min(AvailCount, SafeInfoCount);
6533 SafeInfoCount = AvailCount;
6534
6535 /* Return data to caller */
6536 if (GotCount > 0)
6537 {
6538 Status = RtlULongMult(GotCount, sizeof(FONTFAMILYINFO), &DataSize);
6539 if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
6540 {
6541 DPRINT1("Overflowed.\n");
6542 ExFreePoolWithTag(Info, GDITAG_TEXT);
6543 EngSetLastError(ERROR_INVALID_PARAMETER);
6544 return -1;
6545 }
6546 Status = MmCopyToCaller(UnsafeInfo, Info, DataSize);
6547 if (!NT_SUCCESS(Status))
6548 {
6549 ExFreePoolWithTag(Info, GDITAG_TEXT);
6550 EngSetLastError(ERROR_INVALID_PARAMETER);
6551 return -1;
6552 }
6553 Status = MmCopyToCaller(UnsafeInfoCount, &SafeInfoCount, sizeof(*UnsafeInfoCount));
6554 if (!NT_SUCCESS(Status))
6555 {
6556 ExFreePoolWithTag(Info, GDITAG_TEXT);
6557 EngSetLastError(ERROR_INVALID_PARAMETER);
6558 return -1;
6559 }
6560 }
6561
6562 ExFreePoolWithTag(Info, GDITAG_TEXT);
6563
6564 return GotCount;
6565 }
6566
6567 static inline
6568 LONG
ScaleLong(LONG lValue,PFLOATOBJ pef)6569 ScaleLong(LONG lValue, PFLOATOBJ pef)
6570 {
6571 FLOATOBJ efTemp;
6572
6573 /* Check if we have scaling different from 1 */
6574 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
6575 {
6576 /* Need to multiply */
6577 FLOATOBJ_SetLong(&efTemp, lValue);
6578 FLOATOBJ_Mul(&efTemp, pef);
6579 lValue = FLOATOBJ_GetLong(&efTemp);
6580 }
6581
6582 return lValue;
6583 }
6584
6585 /*
6586 * Calculate X and Y disposition of the text.
6587 * NOTE: The disposition can be negative.
6588 */
6589 static BOOL
IntGetTextDisposition(OUT LONGLONG * pX64,OUT LONGLONG * pY64,IN LPCWSTR String,IN INT Count,IN OPTIONAL LPINT Dx,IN OUT PFONT_CACHE_ENTRY Cache,IN UINT fuOptions,IN BOOL bNoTransform,IN OUT PFONTLINK_CHAIN pChain)6590 IntGetTextDisposition(
6591 OUT LONGLONG *pX64,
6592 OUT LONGLONG *pY64,
6593 IN LPCWSTR String,
6594 IN INT Count,
6595 IN OPTIONAL LPINT Dx,
6596 IN OUT PFONT_CACHE_ENTRY Cache,
6597 IN UINT fuOptions,
6598 IN BOOL bNoTransform,
6599 IN OUT PFONTLINK_CHAIN pChain)
6600 {
6601 LONGLONG X64 = 0, Y64 = 0;
6602 INT i, glyph_index;
6603 FT_BitmapGlyph realglyph;
6604 FT_Face face = Cache->Hashed.Face;
6605 BOOL use_kerning = FT_HAS_KERNING(face);
6606 ULONG previous = 0;
6607 FT_Vector delta, vec;
6608 DWORD ch0, ch1;
6609
6610 ASSERT_FREETYPE_LOCK_HELD();
6611
6612 for (i = 0; i < Count; ++i)
6613 {
6614 ch0 = *String++;
6615 if (IS_HIGH_SURROGATE(ch0))
6616 {
6617 ++i;
6618 if (i >= Count)
6619 return TRUE;
6620
6621 ch1 = *String++;
6622 if (IS_LOW_SURROGATE(ch1))
6623 ch0 = Utf32FromSurrogatePair(ch0, ch1);
6624 }
6625
6626 glyph_index = FontLink_Chain_FindGlyph(pChain, Cache, &face, ch0,
6627 (fuOptions & ETO_GLYPH_INDEX));
6628 Cache->Hashed.GlyphIndex = glyph_index;
6629
6630 realglyph = IntGetRealGlyph(Cache);
6631 if (!realglyph)
6632 return FALSE;
6633
6634 /* Retrieve kerning distance */
6635 if (use_kerning && previous && glyph_index)
6636 {
6637 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
6638 X64 += delta.x;
6639 Y64 -= delta.y;
6640 }
6641
6642 if (NULL == Dx)
6643 {
6644 X64 += realglyph->root.advance.x >> 10;
6645 Y64 -= realglyph->root.advance.y >> 10;
6646 }
6647 else if (fuOptions & ETO_PDY)
6648 {
6649 vec.x = (Dx[2 * i + 0] << 6);
6650 vec.y = (Dx[2 * i + 1] << 6);
6651 if (!bNoTransform)
6652 FT_Vector_Transform(&vec, &Cache->Hashed.matTransform);
6653 X64 += vec.x;
6654 Y64 -= vec.y;
6655 }
6656 else
6657 {
6658 vec.x = (Dx[i] << 6);
6659 vec.y = 0;
6660 if (!bNoTransform)
6661 FT_Vector_Transform(&vec, &Cache->Hashed.matTransform);
6662 X64 += vec.x;
6663 Y64 -= vec.y;
6664 }
6665
6666 previous = glyph_index;
6667 }
6668
6669 *pX64 = X64;
6670 *pY64 = Y64;
6671 return TRUE;
6672 }
6673
6674 VOID APIENTRY
IntEngFillPolygon(IN OUT PDC dc,IN POINTL * pPoints,IN UINT cPoints,IN BRUSHOBJ * BrushObj)6675 IntEngFillPolygon(
6676 IN OUT PDC dc,
6677 IN POINTL *pPoints,
6678 IN UINT cPoints,
6679 IN BRUSHOBJ *BrushObj)
6680 {
6681 SURFACE *psurf = dc->dclevel.pSurface;
6682 RECT Rect;
6683 UINT i;
6684 INT x, y;
6685
6686 ASSERT_DC_PREPARED(dc);
6687 ASSERT(psurf != NULL);
6688
6689 Rect.left = Rect.right = pPoints[0].x;
6690 Rect.top = Rect.bottom = pPoints[0].y;
6691 for (i = 1; i < cPoints; ++i)
6692 {
6693 x = pPoints[i].x;
6694 if (x < Rect.left)
6695 Rect.left = x;
6696 else if (Rect.right < x)
6697 Rect.right = x;
6698
6699 y = pPoints[i].y;
6700 if (y < Rect.top)
6701 Rect.top = y;
6702 else if (Rect.bottom < y)
6703 Rect.bottom = y;
6704 }
6705
6706 IntFillPolygon(dc, dc->dclevel.pSurface, BrushObj, pPoints, cPoints, Rect, &PointZero);
6707 }
6708
6709 VOID
6710 FASTCALL
IntEngFillBox(IN OUT PDC dc,IN INT X,IN INT Y,IN INT Width,IN INT Height,IN BRUSHOBJ * BrushObj)6711 IntEngFillBox(
6712 IN OUT PDC dc,
6713 IN INT X,
6714 IN INT Y,
6715 IN INT Width,
6716 IN INT Height,
6717 IN BRUSHOBJ *BrushObj)
6718 {
6719 RECTL DestRect;
6720 SURFACE *psurf = dc->dclevel.pSurface;
6721
6722 ASSERT_DC_PREPARED(dc);
6723 ASSERT(psurf != NULL);
6724
6725 if (Width < 0)
6726 {
6727 X += Width;
6728 Width = -Width;
6729 }
6730
6731 if (Height < 0)
6732 {
6733 Y += Height;
6734 Height = -Height;
6735 }
6736
6737 DestRect.left = X;
6738 DestRect.right = X + Width;
6739 DestRect.top = Y;
6740 DestRect.bottom = Y + Height;
6741
6742 IntEngBitBlt(&psurf->SurfObj,
6743 NULL,
6744 NULL,
6745 (CLIPOBJ *)&dc->co,
6746 NULL,
6747 &DestRect,
6748 NULL,
6749 NULL,
6750 BrushObj,
6751 &PointZero,
6752 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
6753 }
6754
6755
6756 BOOL
6757 APIENTRY
IntExtTextOutW(IN PDC dc,IN INT XStart,IN INT YStart,IN UINT fuOptions,IN OPTIONAL PRECTL lprc,IN LPCWSTR String,IN INT Count,IN OPTIONAL LPINT Dx,IN DWORD dwCodePage)6758 IntExtTextOutW(
6759 IN PDC dc,
6760 IN INT XStart,
6761 IN INT YStart,
6762 IN UINT fuOptions,
6763 IN OPTIONAL PRECTL lprc,
6764 IN LPCWSTR String,
6765 IN INT Count,
6766 IN OPTIONAL LPINT Dx,
6767 IN DWORD dwCodePage)
6768 {
6769 /*
6770 * FIXME:
6771 * Call EngTextOut, which does the real work (calling DrvTextOut where
6772 * appropriate)
6773 */
6774
6775 PDC_ATTR pdcattr;
6776 SURFOBJ *SurfObj, *SourceGlyphSurf;
6777 SURFACE *psurf;
6778 INT glyph_index, i;
6779 FT_Face face;
6780 FT_BitmapGlyph realglyph;
6781 LONGLONG X64, Y64, RealXStart64, RealYStart64, DeltaX64, DeltaY64;
6782 ULONG previous;
6783 RECTL DestRect, MaskRect;
6784 HBITMAP HSourceGlyph;
6785 SIZEL bitSize;
6786 FONTOBJ *FontObj;
6787 PFONTGDI FontGDI;
6788 PTEXTOBJ TextObj = NULL;
6789 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
6790 POINT Start;
6791 PMATRIX pmxWorldToDevice;
6792 FT_Vector delta, vecAscent64, vecDescent64, vec;
6793 LOGFONTW *plf;
6794 BOOL use_kerning, bResult, DoBreak;
6795 FONT_CACHE_ENTRY Cache;
6796 FT_Matrix mat;
6797 BOOL bNoTransform;
6798 DWORD ch0, ch1;
6799 const DWORD del = 0x7f, nbsp = 0xa0; // DEL is ASCII DELETE and nbsp is a non-breaking space
6800 FONTLINK_CHAIN Chain;
6801 SIZE spaceWidth;
6802
6803 /* Check if String is valid */
6804 if (Count > 0xFFFF || (Count > 0 && String == NULL))
6805 {
6806 EngSetLastError(ERROR_INVALID_PARAMETER);
6807 return FALSE;
6808 }
6809
6810 if (PATH_IsPathOpen(dc->dclevel))
6811 {
6812 return PATH_ExtTextOut(dc,
6813 XStart, YStart,
6814 fuOptions,
6815 lprc,
6816 String, Count,
6817 Dx);
6818 }
6819
6820 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
6821
6822 if (!dc->dclevel.pSurface)
6823 {
6824 /* Memory DC with no surface selected */
6825 bResult = TRUE;
6826 goto Cleanup;
6827 }
6828
6829 pdcattr = dc->pdcattr;
6830 if (pdcattr->flTextAlign & TA_UPDATECP)
6831 {
6832 Start.x = pdcattr->ptlCurrent.x;
6833 Start.y = pdcattr->ptlCurrent.y;
6834 }
6835 else
6836 {
6837 Start.x = XStart;
6838 Start.y = YStart;
6839 }
6840
6841 IntLPtoDP(dc, &Start, 1);
6842 RealXStart64 = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
6843 RealYStart64 = ((LONGLONG)Start.y + dc->ptlDCOrig.y) << 6;
6844
6845 MaskRect.left = 0;
6846 MaskRect.top = 0;
6847
6848 psurf = dc->dclevel.pSurface;
6849 SurfObj = &psurf->SurfObj;
6850
6851 if (pdcattr->iGraphicsMode == GM_ADVANCED)
6852 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6853 else
6854 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
6855
6856 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
6857 DC_vUpdateBackgroundBrush(dc);
6858
6859 if (lprc && (fuOptions & (ETO_CLIPPED | ETO_OPAQUE)))
6860 {
6861 IntLPtoDP(dc, (POINT*)lprc, 2);
6862 lprc->left += dc->ptlDCOrig.x;
6863 lprc->top += dc->ptlDCOrig.y;
6864 lprc->right += dc->ptlDCOrig.x;
6865 lprc->bottom += dc->ptlDCOrig.y;
6866 }
6867
6868 if (lprc && (fuOptions & ETO_OPAQUE))
6869 {
6870 IntEngFillBox(dc,
6871 lprc->left, lprc->top,
6872 lprc->right - lprc->left, lprc->bottom - lprc->top,
6873 &dc->eboBackground.BrushObject);
6874 fuOptions &= ~ETO_OPAQUE;
6875 }
6876 else
6877 {
6878 if (pdcattr->jBkMode == OPAQUE)
6879 {
6880 fuOptions |= ETO_OPAQUE;
6881 }
6882 }
6883
6884 TextObj = RealizeFontInit(pdcattr->hlfntNew);
6885 if (TextObj == NULL)
6886 {
6887 bResult = FALSE;
6888 goto Cleanup;
6889 }
6890
6891 FontObj = TextObj->Font;
6892 ASSERT(FontObj);
6893 FontGDI = ObjToGDI(FontObj, FONT);
6894 ASSERT(FontGDI);
6895
6896 IntLockFreeType();
6897 Cache.Hashed.Face = face = FontGDI->SharedFace->Face;
6898
6899 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6900 Cache.Hashed.lfHeight = plf->lfHeight;
6901 Cache.Hashed.lfWidth = plf->lfWidth;
6902 Cache.Hashed.Aspect.Emu.Bold = EMUBOLD_NEEDED(FontGDI->OriginalWeight, plf->lfWeight);
6903 Cache.Hashed.Aspect.Emu.Italic = (plf->lfItalic && !FontGDI->OriginalItalic);
6904
6905 if (IntIsFontRenderingEnabled())
6906 Cache.Hashed.Aspect.RenderMode = (BYTE)IntGetFontRenderMode(plf);
6907 else
6908 Cache.Hashed.Aspect.RenderMode = (BYTE)FT_RENDER_MODE_MONO;
6909
6910 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
6911 {
6912 IntUnLockFreeType();
6913 bResult = FALSE;
6914 goto Cleanup;
6915 }
6916
6917 FontLink_Chain_Init(&Chain, TextObj, face);
6918
6919 /* Apply lfEscapement */
6920 if (FT_IS_SCALABLE(face) && plf->lfEscapement != 0)
6921 IntEscapeMatrix(&Cache.Hashed.matTransform, plf->lfEscapement);
6922 else
6923 Cache.Hashed.matTransform = identityMat;
6924
6925 /* Apply the world transformation */
6926 IntMatrixFromMx(&mat, pmxWorldToDevice);
6927 FT_Matrix_Multiply(&mat, &Cache.Hashed.matTransform);
6928 FT_Set_Transform(face, &Cache.Hashed.matTransform, NULL);
6929
6930 /* Is there no transformation? */
6931 bNoTransform = ((mat.xy == 0) && (mat.yx == 0) &&
6932 (mat.xx == (1 << 16)) && (mat.yy == (1 << 16)));
6933
6934 /* Calculate the ascent point and the descent point */
6935 vecAscent64.x = 0;
6936 vecAscent64.y = (FontGDI->tmAscent << 6);
6937 FT_Vector_Transform(&vecAscent64, &Cache.Hashed.matTransform);
6938 vecDescent64.x = 0;
6939 vecDescent64.y = -(FontGDI->tmDescent << 6);
6940 FT_Vector_Transform(&vecDescent64, &Cache.Hashed.matTransform);
6941
6942 /* Process the vertical alignment and fix the real starting point. */
6943 #define VALIGN_MASK (TA_TOP | TA_BASELINE | TA_BOTTOM)
6944 if ((pdcattr->flTextAlign & VALIGN_MASK) == TA_BASELINE)
6945 {
6946 NOTHING;
6947 }
6948 else if ((pdcattr->flTextAlign & VALIGN_MASK) == TA_BOTTOM)
6949 {
6950 RealXStart64 -= vecDescent64.x;
6951 RealYStart64 += vecDescent64.y;
6952 }
6953 else /* TA_TOP */
6954 {
6955 RealXStart64 -= vecAscent64.x;
6956 RealYStart64 += vecAscent64.y;
6957 }
6958 #undef VALIGN_MASK
6959
6960 use_kerning = FT_HAS_KERNING(face);
6961
6962 /* Calculate the text width if necessary */
6963 if ((fuOptions & ETO_OPAQUE) || (pdcattr->flTextAlign & (TA_CENTER | TA_RIGHT)))
6964 {
6965 if (!IntGetTextDisposition(&DeltaX64, &DeltaY64, String, Count, Dx, &Cache,
6966 fuOptions, bNoTransform, &Chain))
6967 {
6968 FontLink_Chain_Finish(&Chain);
6969 IntUnLockFreeType();
6970 bResult = FALSE;
6971 goto Cleanup;
6972 }
6973
6974 /* Adjust the horizontal position by horizontal alignment */
6975 if ((pdcattr->flTextAlign & TA_CENTER) == TA_CENTER)
6976 {
6977 RealXStart64 -= DeltaX64 / 2;
6978 RealYStart64 -= DeltaY64 / 2;
6979 }
6980 else if ((pdcattr->flTextAlign & TA_RIGHT) == TA_RIGHT)
6981 {
6982 RealXStart64 -= DeltaX64;
6983 RealYStart64 -= DeltaY64;
6984 }
6985
6986 /* Fill background */
6987 if (fuOptions & ETO_OPAQUE)
6988 {
6989 INT X0 = (RealXStart64 + vecAscent64.x + 32) >> 6;
6990 INT Y0 = (RealYStart64 - vecAscent64.y + 32) >> 6;
6991 INT DX = (DeltaX64 >> 6);
6992 if (Cache.Hashed.matTransform.xy == 0 && Cache.Hashed.matTransform.yx == 0)
6993 {
6994 INT CY = (vecAscent64.y - vecDescent64.y + 32) >> 6;
6995 IntEngFillBox(dc, X0, Y0, DX, CY, &dc->eboBackground.BrushObject);
6996 }
6997 else
6998 {
6999 INT DY = (DeltaY64 >> 6);
7000 INT X1 = ((RealXStart64 + vecDescent64.x + 32) >> 6);
7001 INT Y1 = ((RealYStart64 - vecDescent64.y + 32) >> 6);
7002 POINT Points[4] =
7003 {
7004 { X0, Y0 },
7005 { X0 + DX, Y0 + DY },
7006 { X1 + DX, Y1 + DY },
7007 { X1, Y1 },
7008 };
7009 IntEngFillPolygon(dc, Points, 4, &dc->eboBackground.BrushObject);
7010 }
7011 }
7012 }
7013
7014 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
7015 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
7016
7017 if (pdcattr->ulDirty_ & DIRTY_TEXT)
7018 DC_vUpdateTextBrush(dc);
7019
7020 /*
7021 * The main rendering loop.
7022 */
7023 X64 = RealXStart64;
7024 Y64 = RealYStart64;
7025 previous = 0;
7026 DoBreak = FALSE;
7027 bResult = TRUE; /* Assume success */
7028 for (i = 0; i < Count; ++i)
7029 {
7030 ch0 = *String++;
7031 if (IS_HIGH_SURROGATE(ch0))
7032 {
7033 ++i;
7034 if (i >= Count)
7035 break;
7036
7037 ch1 = *String++;
7038 if (IS_LOW_SURROGATE(ch1))
7039 ch0 = Utf32FromSurrogatePair(ch0, ch1);
7040 }
7041
7042 glyph_index = FontLink_Chain_FindGlyph(&Chain, &Cache, &face, ch0,
7043 (fuOptions & ETO_GLYPH_INDEX));
7044 Cache.Hashed.GlyphIndex = glyph_index;
7045
7046 realglyph = IntGetRealGlyph(&Cache);
7047 if (!realglyph)
7048 {
7049 bResult = FALSE;
7050 break;
7051 }
7052
7053 /* retrieve kerning distance and move pen position */
7054 if (use_kerning && previous && glyph_index && NULL == Dx)
7055 {
7056 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
7057 X64 += delta.x;
7058 Y64 -= delta.y;
7059 }
7060
7061 DPRINT("X64, Y64: %I64d, %I64d\n", X64, Y64);
7062 DPRINT("Advance: %d, %d\n", realglyph->root.advance.x, realglyph->root.advance.y);
7063
7064 bitSize.cx = realglyph->bitmap.width;
7065 bitSize.cy = realglyph->bitmap.rows;
7066
7067 /* Do chars > space & not DEL & not nbsp have a bitSize.cx of zero? */
7068 if (ch0 > L' ' && ch0 != del && ch0 != nbsp && bitSize.cx == 0)
7069 DPRINT1("WARNING: WChar 0x%04x has a bitSize.cx of zero\n", ch0);
7070
7071 /* Don't ignore spaces or non-breaking spaces when computing offset.
7072 * This completes the fix of CORE-11787. */
7073 if ((pdcattr->flTextAlign & TA_UPDATECP) && bitSize.cx == 0 &&
7074 (ch0 == L' ' || ch0 == nbsp)) // Space chars needing x-dim widths
7075 {
7076 IntUnLockFreeType();
7077 /* Get the width of the space character */
7078 TextIntGetTextExtentPoint(dc, TextObj, L" ", 1, 0, NULL, 0, &spaceWidth, 0);
7079 IntLockFreeType();
7080 bitSize.cx = spaceWidth.cx;
7081 realglyph->left = 0;
7082 }
7083
7084 MaskRect.right = realglyph->bitmap.width;
7085 MaskRect.bottom = realglyph->bitmap.rows;
7086
7087 DestRect.left = ((X64 + 32) >> 6) + realglyph->left;
7088 DestRect.right = DestRect.left + bitSize.cx;
7089 DestRect.top = ((Y64 + 32) >> 6) - realglyph->top;
7090 DestRect.bottom = DestRect.top + bitSize.cy;
7091
7092 /* Check if the bitmap has any pixels */
7093 if ((bitSize.cx != 0) && (bitSize.cy != 0))
7094 {
7095 /*
7096 * We should create the bitmap out of the loop at the biggest possible
7097 * glyph size. Then use memset with 0 to clear it and sourcerect to
7098 * limit the work of the transbitblt.
7099 */
7100 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
7101 BMF_8BPP, BMF_TOPDOWN,
7102 realglyph->bitmap.buffer);
7103 if (!HSourceGlyph)
7104 {
7105 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
7106 bResult = FALSE;
7107 break;
7108 }
7109
7110 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
7111 if (!SourceGlyphSurf)
7112 {
7113 EngDeleteSurface((HSURF)HSourceGlyph);
7114 DPRINT1("WARNING: EngLockSurface() failed!\n");
7115 bResult = FALSE;
7116 break;
7117 }
7118
7119 /*
7120 * Use the font data as a mask to paint onto the DCs surface using a
7121 * brush.
7122 */
7123 if (lprc && (fuOptions & ETO_CLIPPED))
7124 {
7125 // We do the check '>=' instead of '>' to possibly save an iteration
7126 // through this loop, since it's breaking after the drawing is done,
7127 // and x is always incremented.
7128 if (DestRect.right >= lprc->right)
7129 {
7130 DestRect.right = lprc->right;
7131 DoBreak = TRUE;
7132 }
7133
7134 if (DestRect.bottom >= lprc->bottom)
7135 {
7136 DestRect.bottom = lprc->bottom;
7137 }
7138 }
7139
7140 if (!IntEngMaskBlt(SurfObj,
7141 SourceGlyphSurf,
7142 (CLIPOBJ *)&dc->co,
7143 &exloRGB2Dst.xlo,
7144 &exloDst2RGB.xlo,
7145 &DestRect,
7146 (PPOINTL)&MaskRect,
7147 &dc->eboText.BrushObject,
7148 &PointZero))
7149 {
7150 DPRINT1("Failed to MaskBlt a glyph!\n");
7151 }
7152
7153 EngUnlockSurface(SourceGlyphSurf);
7154 EngDeleteSurface((HSURF)HSourceGlyph);
7155 }
7156
7157 if (DoBreak)
7158 break;
7159
7160 if (NULL == Dx)
7161 {
7162 X64 += realglyph->root.advance.x >> 10;
7163 Y64 -= realglyph->root.advance.y >> 10;
7164 }
7165 else if (fuOptions & ETO_PDY)
7166 {
7167 vec.x = (Dx[2 * i + 0] << 6);
7168 vec.y = (Dx[2 * i + 1] << 6);
7169 if (!bNoTransform)
7170 FT_Vector_Transform(&vec, &Cache.Hashed.matTransform);
7171 X64 += vec.x;
7172 Y64 -= vec.y;
7173 }
7174 else
7175 {
7176 vec.x = (Dx[i] << 6);
7177 vec.y = 0;
7178 if (!bNoTransform)
7179 FT_Vector_Transform(&vec, &Cache.Hashed.matTransform);
7180 X64 += vec.x;
7181 Y64 -= vec.y;
7182 }
7183
7184 DPRINT("New X64, New Y64: %I64d, %I64d\n", X64, Y64);
7185
7186 previous = glyph_index;
7187 }
7188 /* Don't update position if String == NULL. Fixes CORE-19721. */
7189 if ((pdcattr->flTextAlign & TA_UPDATECP) && String)
7190 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
7191
7192 if (plf->lfUnderline || plf->lfStrikeOut) /* Underline or strike-out? */
7193 {
7194 /* Calculate the position and the thickness */
7195 INT underline_position, thickness;
7196 FT_Vector vecA64, vecB64;
7197
7198 DeltaX64 = X64 - RealXStart64;
7199 DeltaY64 = Y64 - RealYStart64;
7200
7201 if (!face->units_per_EM)
7202 {
7203 underline_position = 0;
7204 thickness = 1;
7205 }
7206 else
7207 {
7208 underline_position =
7209 face->underline_position * face->size->metrics.y_ppem / face->units_per_EM;
7210 thickness =
7211 face->underline_thickness * face->size->metrics.y_ppem / face->units_per_EM;
7212 if (thickness <= 0)
7213 thickness = 1;
7214 }
7215
7216 if (plf->lfUnderline) /* Draw underline */
7217 {
7218 vecA64.x = 0;
7219 vecA64.y = (-underline_position - thickness / 2) << 6;
7220 vecB64.x = 0;
7221 vecB64.y = vecA64.y + (thickness << 6);
7222 FT_Vector_Transform(&vecA64, &Cache.Hashed.matTransform);
7223 FT_Vector_Transform(&vecB64, &Cache.Hashed.matTransform);
7224 {
7225 INT X0 = (RealXStart64 - vecA64.x + 32) >> 6;
7226 INT Y0 = (RealYStart64 + vecA64.y + 32) >> 6;
7227 INT DX = (DeltaX64 >> 6);
7228 if (Cache.Hashed.matTransform.xy == 0 && Cache.Hashed.matTransform.yx == 0)
7229 {
7230 INT CY = (vecB64.y - vecA64.y + 32) >> 6;
7231 IntEngFillBox(dc, X0, Y0, DX, CY, &dc->eboText.BrushObject);
7232 }
7233 else
7234 {
7235 INT DY = (DeltaY64 >> 6);
7236 INT X1 = X0 + ((vecA64.x - vecB64.x + 32) >> 6);
7237 INT Y1 = Y0 + ((vecB64.y - vecA64.y + 32) >> 6);
7238 POINT Points[4] =
7239 {
7240 { X0, Y0 },
7241 { X0 + DX, Y0 + DY },
7242 { X1 + DX, Y1 + DY },
7243 { X1, Y1 },
7244 };
7245 IntEngFillPolygon(dc, Points, 4, &dc->eboText.BrushObject);
7246 }
7247 }
7248 }
7249
7250 if (plf->lfStrikeOut) /* Draw strike-out */
7251 {
7252 vecA64.x = 0;
7253 vecA64.y = -(FontGDI->tmAscent << 6) / 3;
7254 vecB64.x = 0;
7255 vecB64.y = vecA64.y + (thickness << 6);
7256 FT_Vector_Transform(&vecA64, &Cache.Hashed.matTransform);
7257 FT_Vector_Transform(&vecB64, &Cache.Hashed.matTransform);
7258 {
7259 INT X0 = (RealXStart64 - vecA64.x + 32) >> 6;
7260 INT Y0 = (RealYStart64 + vecA64.y + 32) >> 6;
7261 INT DX = (DeltaX64 >> 6);
7262 if (Cache.Hashed.matTransform.xy == 0 && Cache.Hashed.matTransform.yx == 0)
7263 {
7264 INT CY = (vecB64.y - vecA64.y + 32) >> 6;
7265 IntEngFillBox(dc, X0, Y0, DX, CY, &dc->eboText.BrushObject);
7266 }
7267 else
7268 {
7269 INT DY = (DeltaY64 >> 6);
7270 INT X1 = X0 + ((vecA64.x - vecB64.x + 32) >> 6);
7271 INT Y1 = Y0 + ((vecB64.y - vecA64.y + 32) >> 6);
7272 POINT Points[4] =
7273 {
7274 { X0, Y0 },
7275 { X0 + DX, Y0 + DY },
7276 { X1 + DX, Y1 + DY },
7277 { X1, Y1 },
7278 };
7279 IntEngFillPolygon(dc, Points, 4, &dc->eboText.BrushObject);
7280 }
7281 }
7282 }
7283 }
7284
7285 FontLink_Chain_Finish(&Chain);
7286
7287 IntUnLockFreeType();
7288
7289 EXLATEOBJ_vCleanup(&exloRGB2Dst);
7290 EXLATEOBJ_vCleanup(&exloDst2RGB);
7291
7292 Cleanup:
7293 DC_vFinishBlit(dc, NULL);
7294
7295 if (TextObj != NULL)
7296 TEXTOBJ_UnlockText(TextObj);
7297
7298 return bResult;
7299 }
7300
7301
7302 BOOL
7303 APIENTRY
GreExtTextOutW(IN HDC hDC,IN INT XStart,IN INT YStart,IN UINT fuOptions,IN OPTIONAL PRECTL lprc,IN LPCWSTR String,IN INT Count,IN OPTIONAL LPINT Dx,IN DWORD dwCodePage)7304 GreExtTextOutW(
7305 IN HDC hDC,
7306 IN INT XStart,
7307 IN INT YStart,
7308 IN UINT fuOptions,
7309 IN OPTIONAL PRECTL lprc,
7310 IN LPCWSTR String,
7311 IN INT Count,
7312 IN OPTIONAL LPINT Dx,
7313 IN DWORD dwCodePage)
7314 {
7315 BOOL bResult;
7316 DC *dc;
7317
7318 // TODO: Write test-cases to exactly match real Windows in different
7319 // bad parameters (e.g. does Windows check the DC or the RECT first?).
7320 dc = DC_LockDc(hDC);
7321 if (!dc)
7322 {
7323 EngSetLastError(ERROR_INVALID_HANDLE);
7324 return FALSE;
7325 }
7326
7327 bResult = IntExtTextOutW( dc,
7328 XStart,
7329 YStart,
7330 fuOptions,
7331 lprc,
7332 String,
7333 Count,
7334 Dx,
7335 dwCodePage );
7336
7337 DC_UnlockDc(dc);
7338
7339 return bResult;
7340 }
7341
7342 #define STACK_TEXT_BUFFER_SIZE 512
7343
7344 BOOL
7345 APIENTRY
NtGdiExtTextOutW(IN HDC hDC,IN INT XStart,IN INT YStart,IN UINT fuOptions,IN OPTIONAL LPRECT UnsafeRect,IN LPWSTR UnsafeString,IN INT Count,IN OPTIONAL LPINT UnsafeDx,IN DWORD dwCodePage)7346 NtGdiExtTextOutW(
7347 IN HDC hDC,
7348 IN INT XStart,
7349 IN INT YStart,
7350 IN UINT fuOptions,
7351 IN OPTIONAL LPRECT UnsafeRect,
7352 IN LPWSTR UnsafeString,
7353 IN INT Count,
7354 IN OPTIONAL LPINT UnsafeDx,
7355 IN DWORD dwCodePage)
7356 {
7357 BOOL Result = FALSE;
7358 NTSTATUS Status = STATUS_SUCCESS;
7359 RECTL SafeRect;
7360 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
7361 PVOID Buffer = LocalBuffer;
7362 LPCWSTR SafeString = NULL;
7363 LPINT SafeDx = NULL;
7364 ULONG BufSize, StringSize, DxSize = 0;
7365
7366 /* Check if String is valid */
7367 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
7368 {
7369 EngSetLastError(ERROR_INVALID_PARAMETER);
7370 return FALSE;
7371 }
7372
7373 if (Count > 0)
7374 {
7375 /* Calculate buffer size for string and Dx values */
7376 BufSize = StringSize = Count * sizeof(WCHAR);
7377 if (UnsafeDx)
7378 {
7379 /* If ETO_PDY is specified, we have pairs of INTs */
7380 DxSize = (Count * sizeof(INT)) * ((fuOptions & ETO_PDY) ? 2 : 1);
7381 BufSize += DxSize;
7382 }
7383
7384 /* Check if our local buffer is large enough */
7385 if (BufSize > sizeof(LocalBuffer))
7386 {
7387 /* It's not, allocate a temp buffer */
7388 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
7389 if (!Buffer)
7390 {
7391 return FALSE;
7392 }
7393 }
7394
7395 /* Probe and copy user mode data to the buffer */
7396 _SEH2_TRY
7397 {
7398 /* Put the Dx before the String to assure alignment of 4 */
7399 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
7400
7401 /* Probe and copy the string */
7402 ProbeForRead(UnsafeString, StringSize, 1);
7403 RtlCopyMemory((PVOID)SafeString, UnsafeString, StringSize);
7404
7405 /* If we have Dx values... */
7406 if (UnsafeDx)
7407 {
7408 /* ... probe and copy them */
7409 SafeDx = Buffer;
7410 ProbeForRead(UnsafeDx, DxSize, 1);
7411 RtlCopyMemory(SafeDx, UnsafeDx, DxSize);
7412 }
7413 }
7414 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7415 {
7416 Status = _SEH2_GetExceptionCode();
7417 }
7418 _SEH2_END
7419 if (!NT_SUCCESS(Status))
7420 {
7421 goto cleanup;
7422 }
7423 }
7424
7425 /* If we have a rect, copy it */
7426 if (UnsafeRect)
7427 {
7428 _SEH2_TRY
7429 {
7430 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
7431 SafeRect = *UnsafeRect;
7432 }
7433 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7434 {
7435 Status = _SEH2_GetExceptionCode();
7436 }
7437 _SEH2_END
7438 if (!NT_SUCCESS(Status))
7439 {
7440 goto cleanup;
7441 }
7442 }
7443
7444 /* Finally call the internal routine */
7445 Result = GreExtTextOutW(hDC,
7446 XStart,
7447 YStart,
7448 fuOptions,
7449 &SafeRect,
7450 SafeString,
7451 Count,
7452 SafeDx,
7453 dwCodePage);
7454
7455 cleanup:
7456 /* If we allocated a buffer, free it */
7457 if (Buffer != LocalBuffer)
7458 {
7459 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
7460 }
7461
7462 return Result;
7463 }
7464
7465
7466 /*
7467 * @implemented
7468 */
7469 BOOL
7470 APIENTRY
NtGdiGetCharABCWidthsW(IN HDC hDC,IN UINT FirstChar,IN ULONG Count,IN OPTIONAL PWCHAR UnSafepwch,IN FLONG fl,OUT PVOID Buffer)7471 NtGdiGetCharABCWidthsW(
7472 IN HDC hDC,
7473 IN UINT FirstChar,
7474 IN ULONG Count,
7475 IN OPTIONAL PWCHAR UnSafepwch,
7476 IN FLONG fl,
7477 OUT PVOID Buffer)
7478 {
7479 LPABC SafeBuff;
7480 LPABCFLOAT SafeBuffF = NULL;
7481 PDC dc;
7482 PDC_ATTR pdcattr;
7483 PTEXTOBJ TextObj;
7484 PFONTGDI FontGDI;
7485 FT_Face face;
7486 FT_CharMap charmap, found = NULL;
7487 UINT i, glyph_index, BufferSize;
7488 HFONT hFont = 0;
7489 NTSTATUS Status = STATUS_SUCCESS;
7490 PWCHAR Safepwch = NULL;
7491 LOGFONTW *plf;
7492
7493 if (!Buffer)
7494 {
7495 EngSetLastError(ERROR_INVALID_PARAMETER);
7496 return FALSE;
7497 }
7498
7499 if (UnSafepwch)
7500 {
7501 UINT pwchSize = Count * sizeof(WCHAR);
7502 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
7503
7504 if(!Safepwch)
7505 {
7506 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
7507 return FALSE;
7508 }
7509
7510 _SEH2_TRY
7511 {
7512 ProbeForRead(UnSafepwch, pwchSize, 1);
7513 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
7514 }
7515 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7516 {
7517 Status = _SEH2_GetExceptionCode();
7518 }
7519 _SEH2_END;
7520 }
7521
7522 if (!NT_SUCCESS(Status))
7523 {
7524 if(Safepwch)
7525 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7526
7527 EngSetLastError(Status);
7528 return FALSE;
7529 }
7530
7531 BufferSize = Count * sizeof(ABC); // Same size!
7532 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
7533 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
7534 if (SafeBuff == NULL)
7535 {
7536
7537 if(Safepwch)
7538 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7539
7540 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
7541 return FALSE;
7542 }
7543
7544 dc = DC_LockDc(hDC);
7545 if (dc == NULL)
7546 {
7547 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7548
7549 if(Safepwch)
7550 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7551
7552 EngSetLastError(ERROR_INVALID_HANDLE);
7553 return FALSE;
7554 }
7555 pdcattr = dc->pdcattr;
7556 hFont = pdcattr->hlfntNew;
7557 TextObj = RealizeFontInit(hFont);
7558
7559 DC_UnlockDc(dc);
7560
7561 if (TextObj == NULL)
7562 {
7563 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7564
7565 if(Safepwch)
7566 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7567
7568 EngSetLastError(ERROR_INVALID_HANDLE);
7569 return FALSE;
7570 }
7571
7572 FontGDI = ObjToGDI(TextObj->Font, FONT);
7573
7574 face = FontGDI->SharedFace->Face;
7575 if (face->charmap == NULL)
7576 {
7577 for (i = 0; i < (UINT)face->num_charmaps; i++)
7578 {
7579 charmap = face->charmaps[i];
7580 if (charmap->encoding != 0)
7581 {
7582 found = charmap;
7583 break;
7584 }
7585 }
7586
7587 if (!found)
7588 {
7589 DPRINT1("WARNING: Could not find desired charmap!\n");
7590 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7591
7592 if(Safepwch)
7593 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7594
7595 EngSetLastError(ERROR_INVALID_HANDLE);
7596 return FALSE;
7597 }
7598
7599 IntLockFreeType();
7600 FT_Set_Charmap(face, found);
7601 IntUnLockFreeType();
7602 }
7603
7604 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
7605
7606 // NOTE: GetCharABCWidths simply ignores lfEscapement and XFORM.
7607 IntLockFreeType();
7608 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
7609 FT_Set_Transform(face, NULL, NULL);
7610
7611 for (i = FirstChar; i < FirstChar+Count; i++)
7612 {
7613 int adv, lsb, bbx, left, right;
7614
7615 if (Safepwch)
7616 {
7617 glyph_index = get_glyph_index_flagged(face, Safepwch[i - FirstChar], (fl & GCABCW_INDICES));
7618 }
7619 else
7620 {
7621 glyph_index = get_glyph_index_flagged(face, i, (fl & GCABCW_INDICES));
7622 }
7623 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
7624
7625 left = (INT)face->glyph->metrics.horiBearingX & -64;
7626 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
7627 adv = (face->glyph->advance.x + 32) >> 6;
7628
7629 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
7630 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
7631
7632 lsb = left >> 6;
7633 bbx = (right - left) >> 6;
7634 /*
7635 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
7636 */
7637 if (!fl)
7638 {
7639 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
7640 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
7641 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
7642 }
7643 else
7644 {
7645 SafeBuff[i - FirstChar].abcA = lsb;
7646 SafeBuff[i - FirstChar].abcB = bbx;
7647 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
7648 }
7649 }
7650 IntUnLockFreeType();
7651 TEXTOBJ_UnlockText(TextObj);
7652 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
7653
7654 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7655
7656 if(Safepwch)
7657 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7658
7659 if (!NT_SUCCESS(Status))
7660 {
7661 SetLastNtError(Status);
7662 return FALSE;
7663 }
7664
7665 DPRINT("NtGdiGetCharABCWidths Worked!\n");
7666 return TRUE;
7667 }
7668
7669 /*
7670 * @implemented
7671 */
7672 BOOL
7673 APIENTRY
NtGdiGetCharWidthW(IN HDC hDC,IN UINT FirstChar,IN UINT Count,IN OPTIONAL PWCHAR UnSafepwc,IN FLONG fl,OUT PVOID Buffer)7674 NtGdiGetCharWidthW(
7675 IN HDC hDC,
7676 IN UINT FirstChar,
7677 IN UINT Count,
7678 IN OPTIONAL PWCHAR UnSafepwc,
7679 IN FLONG fl,
7680 OUT PVOID Buffer)
7681 {
7682 NTSTATUS Status = STATUS_SUCCESS;
7683 LPINT SafeBuff;
7684 PFLOAT SafeBuffF = NULL;
7685 PDC dc;
7686 PDC_ATTR pdcattr;
7687 PTEXTOBJ TextObj;
7688 PFONTGDI FontGDI;
7689 FT_Face face;
7690 FT_CharMap charmap, found = NULL;
7691 UINT i, glyph_index, BufferSize;
7692 HFONT hFont = 0;
7693 PWCHAR Safepwc = NULL;
7694 LOGFONTW *plf;
7695
7696 if (UnSafepwc)
7697 {
7698 UINT pwcSize = Count * sizeof(WCHAR);
7699 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
7700
7701 if(!Safepwc)
7702 {
7703 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
7704 return FALSE;
7705 }
7706 _SEH2_TRY
7707 {
7708 ProbeForRead(UnSafepwc, pwcSize, 1);
7709 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
7710 }
7711 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7712 {
7713 Status = _SEH2_GetExceptionCode();
7714 }
7715 _SEH2_END;
7716 }
7717
7718 if (!NT_SUCCESS(Status))
7719 {
7720 EngSetLastError(Status);
7721 return FALSE;
7722 }
7723
7724 BufferSize = Count * sizeof(INT); // Same size!
7725 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
7726 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
7727 if (SafeBuff == NULL)
7728 {
7729 if(Safepwc)
7730 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7731
7732 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
7733 return FALSE;
7734 }
7735
7736 dc = DC_LockDc(hDC);
7737 if (dc == NULL)
7738 {
7739 if(Safepwc)
7740 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7741
7742 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7743 EngSetLastError(ERROR_INVALID_HANDLE);
7744 return FALSE;
7745 }
7746 pdcattr = dc->pdcattr;
7747 hFont = pdcattr->hlfntNew;
7748 TextObj = RealizeFontInit(hFont);
7749 DC_UnlockDc(dc);
7750
7751 if (TextObj == NULL)
7752 {
7753 if(Safepwc)
7754 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7755
7756 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7757 EngSetLastError(ERROR_INVALID_HANDLE);
7758 return FALSE;
7759 }
7760
7761 FontGDI = ObjToGDI(TextObj->Font, FONT);
7762
7763 face = FontGDI->SharedFace->Face;
7764 if (face->charmap == NULL)
7765 {
7766 for (i = 0; i < (UINT)face->num_charmaps; i++)
7767 {
7768 charmap = face->charmaps[i];
7769 if (charmap->encoding != 0)
7770 {
7771 found = charmap;
7772 break;
7773 }
7774 }
7775
7776 if (!found)
7777 {
7778 DPRINT1("WARNING: Could not find desired charmap!\n");
7779
7780 if(Safepwc)
7781 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7782
7783 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7784 EngSetLastError(ERROR_INVALID_HANDLE);
7785 return FALSE;
7786 }
7787
7788 IntLockFreeType();
7789 FT_Set_Charmap(face, found);
7790 IntUnLockFreeType();
7791 }
7792
7793 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
7794
7795 // NOTE: GetCharWidth simply ignores lfEscapement and XFORM.
7796 IntLockFreeType();
7797 IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
7798 FT_Set_Transform(face, NULL, NULL);
7799
7800 for (i = FirstChar; i < FirstChar+Count; i++)
7801 {
7802 if (Safepwc)
7803 {
7804 glyph_index = get_glyph_index_flagged(face, Safepwc[i - FirstChar], (fl & GCW_INDICES));
7805 }
7806 else
7807 {
7808 glyph_index = get_glyph_index_flagged(face, i, (fl & GCW_INDICES));
7809 }
7810 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
7811 if (!fl)
7812 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
7813 else
7814 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
7815 }
7816 IntUnLockFreeType();
7817 TEXTOBJ_UnlockText(TextObj);
7818 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
7819
7820 if(Safepwc)
7821 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7822
7823 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7824 return TRUE;
7825 }
7826
7827
7828 /*
7829 * @implemented
7830 */
7831 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
7832 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
7833 // NOTE: See also GreGetGlyphIndicesW.
7834 __kernel_entry
7835 W32KAPI
7836 DWORD
7837 APIENTRY
NtGdiGetGlyphIndicesW(_In_ HDC hdc,_In_reads_opt_ (cwc)LPCWSTR pwc,_In_ INT cwc,_Out_writes_opt_ (cwc)LPWORD pgi,_In_ DWORD iMode)7838 NtGdiGetGlyphIndicesW(
7839 _In_ HDC hdc,
7840 _In_reads_opt_(cwc) LPCWSTR pwc,
7841 _In_ INT cwc,
7842 _Out_writes_opt_(cwc) LPWORD pgi,
7843 _In_ DWORD iMode)
7844 {
7845 PDC dc;
7846 PDC_ATTR pdcattr;
7847 PTEXTOBJ TextObj;
7848 PFONTGDI FontGDI;
7849 HFONT hFont = NULL;
7850 NTSTATUS Status = STATUS_SUCCESS;
7851 OUTLINETEXTMETRICW *potm;
7852 INT i;
7853 WCHAR DefChar = 0xffff;
7854 PWSTR Buffer = NULL;
7855 ULONG Size, pwcSize;
7856 PWSTR Safepwc = NULL;
7857 LPCWSTR UnSafepwc = pwc;
7858 LPWORD UnSafepgi = pgi;
7859 FT_Face Face;
7860 TT_OS2 *pOS2;
7861
7862 if (cwc < 0)
7863 {
7864 DPRINT1("cwc < 0\n");
7865 return GDI_ERROR;
7866 }
7867
7868 if (!UnSafepwc && !UnSafepgi && cwc > 0)
7869 {
7870 DPRINT1("!UnSafepwc && !UnSafepgi && cwc > 0\n");
7871 return GDI_ERROR;
7872 }
7873
7874 if (!UnSafepwc != !UnSafepgi)
7875 {
7876 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
7877 return GDI_ERROR;
7878 }
7879
7880 /* Get FontGDI */
7881 dc = DC_LockDc(hdc);
7882 if (!dc)
7883 {
7884 DPRINT1("!DC_LockDC\n");
7885 return GDI_ERROR;
7886 }
7887 pdcattr = dc->pdcattr;
7888 hFont = pdcattr->hlfntNew;
7889 TextObj = RealizeFontInit(hFont);
7890 DC_UnlockDc(dc);
7891 if (!TextObj)
7892 {
7893 DPRINT1("!TextObj\n");
7894 return GDI_ERROR;
7895 }
7896 FontGDI = ObjToGDI(TextObj->Font, FONT);
7897 TEXTOBJ_UnlockText(TextObj);
7898
7899 if (cwc == 0)
7900 {
7901 if (!UnSafepwc && !UnSafepgi)
7902 {
7903 Face = FontGDI->SharedFace->Face;
7904 return Face->num_glyphs;
7905 }
7906 else
7907 {
7908 Status = STATUS_UNSUCCESSFUL;
7909 goto ErrorRet;
7910 }
7911 }
7912
7913 Buffer = ExAllocatePoolWithTag(PagedPool, cwc * sizeof(WORD), GDITAG_TEXT);
7914 if (!Buffer)
7915 {
7916 DPRINT1("ExAllocatePoolWithTag\n");
7917 return GDI_ERROR;
7918 }
7919
7920 /* Get DefChar */
7921 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
7922 {
7923 DefChar = 0xffff;
7924 }
7925 else
7926 {
7927 Face = FontGDI->SharedFace->Face;
7928 if (FT_IS_SFNT(Face))
7929 {
7930 IntLockFreeType();
7931 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
7932 DefChar = (pOS2->usDefaultChar ? get_glyph_index(Face, pOS2->usDefaultChar) : 0);
7933 IntUnLockFreeType();
7934 }
7935 else
7936 {
7937 ASSERT_FREETYPE_LOCK_NOT_HELD();
7938 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL, FALSE);
7939 if (!Size)
7940 {
7941 Status = STATUS_UNSUCCESSFUL;
7942 DPRINT1("!Size\n");
7943 goto ErrorRet;
7944 }
7945 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
7946 if (!potm)
7947 {
7948 Status = STATUS_INSUFFICIENT_RESOURCES;
7949 DPRINT1("!potm\n");
7950 goto ErrorRet;
7951 }
7952 ASSERT_FREETYPE_LOCK_NOT_HELD();
7953 Size = IntGetOutlineTextMetrics(FontGDI, Size, potm, FALSE);
7954 if (Size)
7955 DefChar = potm->otmTextMetrics.tmDefaultChar;
7956 ExFreePoolWithTag(potm, GDITAG_TEXT);
7957 }
7958 }
7959
7960 /* Allocate for Safepwc */
7961 pwcSize = cwc * sizeof(WCHAR);
7962 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
7963 if (!Safepwc)
7964 {
7965 Status = STATUS_NO_MEMORY;
7966 DPRINT1("!Safepwc\n");
7967 goto ErrorRet;
7968 }
7969
7970 _SEH2_TRY
7971 {
7972 ProbeForRead(UnSafepwc, pwcSize, 1);
7973 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
7974 }
7975 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7976 {
7977 Status = _SEH2_GetExceptionCode();
7978 }
7979 _SEH2_END;
7980
7981 if (!NT_SUCCESS(Status))
7982 {
7983 DPRINT1("Status: %08lX\n", Status);
7984 goto ErrorRet;
7985 }
7986
7987 /* Get glyph indeces */
7988 IntLockFreeType();
7989 for (i = 0; i < cwc; i++)
7990 {
7991 Buffer[i] = get_glyph_index(FontGDI->SharedFace->Face, Safepwc[i]);
7992 if (Buffer[i] == 0)
7993 {
7994 Buffer[i] = DefChar;
7995 }
7996 }
7997 IntUnLockFreeType();
7998
7999 _SEH2_TRY
8000 {
8001 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
8002 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
8003 }
8004 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
8005 {
8006 Status = _SEH2_GetExceptionCode();
8007 }
8008 _SEH2_END;
8009
8010 ErrorRet:
8011 if (Buffer != NULL)
8012 {
8013 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
8014 }
8015 if (Safepwc != NULL)
8016 {
8017 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
8018 }
8019
8020 if (NT_SUCCESS(Status))
8021 return cwc;
8022
8023 return GDI_ERROR;
8024 }
8025
8026 /* EOF */
8027