[WIN32SS] Rewrite font selection code. Patch by Katayama Hirofumi MZ. CORE-6621
[reactos.git] / reactos / win32ss / gdi / ntgdi / freetype.c
1 /*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/freetype.c
5 * PURPOSE: FreeType font engine interface
6 * PROGRAMMERS: Copyright 2001 Huw D M Davies for CodeWeavers.
7 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
8 * Copyright 2016-2017 Katayama Hirofumi MZ.
9 */
10
11 /** Includes ******************************************************************/
12
13 #include <win32k.h>
14
15 #include FT_GLYPH_H
16 #include FT_TYPE1_TABLES_H
17 #include FT_TRUETYPE_TABLES_H
18 #include FT_TRUETYPE_TAGS_H
19 #include FT_TRIGONOMETRY_H
20 #include FT_BITMAP_H
21 #include FT_OUTLINE_H
22 #include FT_WINFONTS_H
23 #include FT_SFNT_NAMES_H
24 #include FT_SYNTHESIS_H
25 #include FT_TRUETYPE_IDS_H
26
27 #ifndef FT_INTERNAL_INTERNAL_H
28 #define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h>
29 #include FT_INTERNAL_INTERNAL_H
30 #endif
31 #include FT_INTERNAL_TRUETYPE_TYPES_H
32
33 #include <gdi/eng/floatobj.h>
34
35 #define NDEBUG
36 #include <debug.h>
37
38 /* TPMF_FIXED_PITCH is confusing; brain-dead api */
39 #ifndef _TMPF_VARIABLE_PITCH
40 #define _TMPF_VARIABLE_PITCH TMPF_FIXED_PITCH
41 #endif
42
43 extern const MATRIX gmxWorldToDeviceDefault;
44 extern const MATRIX gmxWorldToPageDefault;
45
46 // HACK!! Fix XFORMOBJ then use 1:16 / 16:1
47 #define gmxWorldToDeviceDefault gmxWorldToPageDefault
48
49 FT_Library library;
50
51 /* special font names */
52 static const UNICODE_STRING MarlettW = RTL_CONSTANT_STRING(L"Marlett");
53 static const UNICODE_STRING SystemW = RTL_CONSTANT_STRING(L"System");
54 static const UNICODE_STRING FixedSysW = RTL_CONSTANT_STRING(L"FixedSys");
55
56 /* registry */
57 static UNICODE_STRING FontRegPath =
58 RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
59
60 static PSHARED_FACE
61 SharedFace_Create(FT_Face Face)
62 {
63 PSHARED_FACE Ptr;
64 Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
65 if (Ptr)
66 {
67 Ptr->Face = Face;
68 Ptr->RefCount = 1;
69 }
70 return Ptr;
71 }
72
73 static void
74 SharedFace_AddRef(PSHARED_FACE Ptr)
75 {
76 ++Ptr->RefCount;
77 }
78
79 static void
80 SharedFace_Release(PSHARED_FACE Ptr)
81 {
82 if (Ptr->RefCount <= 0)
83 return;
84
85 --Ptr->RefCount;
86 if (Ptr->RefCount == 0)
87 {
88 FT_Done_Face(Ptr->Face);
89 ExFreePoolWithTag(Ptr, TAG_FONT);
90 }
91 }
92
93 typedef struct _FONT_ENTRY
94 {
95 LIST_ENTRY ListEntry;
96 FONTGDI *Font;
97 UNICODE_STRING FaceName;
98 BYTE NotEnum;
99 } FONT_ENTRY, *PFONT_ENTRY;
100
101 /* The FreeType library is not thread safe, so we have
102 to serialize access to it */
103 static PFAST_MUTEX FreeTypeLock;
104
105 static LIST_ENTRY FontListHead;
106 static PFAST_MUTEX FontListLock;
107 static BOOL RenderingEnabled = TRUE;
108
109 #define IntLockGlobalFonts \
110 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FontListLock)
111
112 #define IntUnLockGlobalFonts \
113 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
114
115 #define IntLockFreeType \
116 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
117
118 #define IntUnLockFreeType \
119 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock)
120
121 #define MAX_FONT_CACHE 256
122
123 typedef struct _FONT_CACHE_ENTRY
124 {
125 LIST_ENTRY ListEntry;
126 int GlyphIndex;
127 FT_Face Face;
128 FT_BitmapGlyph BitmapGlyph;
129 int Height;
130 MATRIX mxWorldToDevice;
131 } FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY;
132 static LIST_ENTRY FontCacheListHead;
133 static UINT FontCacheNumEntries;
134
135 static PWCHAR ElfScripts[32] = /* These are in the order of the fsCsb[0] bits */
136 {
137 L"Western", /* 00 */
138 L"Central_European",
139 L"Cyrillic",
140 L"Greek",
141 L"Turkish",
142 L"Hebrew",
143 L"Arabic",
144 L"Baltic",
145 L"Vietnamese", /* 08 */
146 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */
147 L"Thai",
148 L"Japanese",
149 L"CHINESE_GB2312",
150 L"Hangul",
151 L"CHINESE_BIG5",
152 L"Hangul(Johab)",
153 NULL, NULL, /* 23 */
154 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
155 L"Symbol" /* 31 */
156 };
157
158 /*
159 * For TranslateCharsetInfo
160 */
161 #define CP_SYMBOL 42
162 #define MAXTCIINDEX 32
163 static const CHARSETINFO FontTci[MAXTCIINDEX] =
164 {
165 /* ANSI */
166 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
167 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
168 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
169 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
170 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
171 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
172 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
173 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
174 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
175 /* reserved by ANSI */
176 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
177 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
178 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
179 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
180 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
181 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
182 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
183 /* ANSI and OEM */
184 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
185 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
186 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
187 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
188 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
189 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
190 /* Reserved for alternate ANSI and OEM */
191 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
192 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
193 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
194 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
195 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
196 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
197 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
198 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
199 /* Reserved for system */
200 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
201 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
202 };
203
204 BOOL FASTCALL
205 InitFontSupport(VOID)
206 {
207 ULONG ulError;
208
209 InitializeListHead(&FontListHead);
210 InitializeListHead(&FontCacheListHead);
211 FontCacheNumEntries = 0;
212 /* Fast Mutexes must be allocated from non paged pool */
213 FontListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
214 if (FontListLock == NULL)
215 {
216 return FALSE;
217 }
218
219 ExInitializeFastMutex(FontListLock);
220 FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
221 if (FreeTypeLock == NULL)
222 {
223 return FALSE;
224 }
225 ExInitializeFastMutex(FreeTypeLock);
226
227 ulError = FT_Init_FreeType(&library);
228 if (ulError)
229 {
230 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
231 return FALSE;
232 }
233
234 IntLoadSystemFonts();
235
236 return TRUE;
237 }
238
239 VOID
240 FtSetCoordinateTransform(
241 FT_Face face,
242 PMATRIX pmx)
243 {
244 FT_Matrix ftmatrix;
245 FLOATOBJ efTemp;
246
247 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
248 efTemp = pmx->efM11;
249 FLOATOBJ_MulLong(&efTemp, 0x00010000);
250 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
251
252 efTemp = pmx->efM12;
253 FLOATOBJ_MulLong(&efTemp, 0x00010000);
254 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
255
256 efTemp = pmx->efM21;
257 FLOATOBJ_MulLong(&efTemp, 0x00010000);
258 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
259
260 efTemp = pmx->efM22;
261 FLOATOBJ_MulLong(&efTemp, 0x00010000);
262 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
263
264 /* Set the transformation matrix */
265 FT_Set_Transform(face, &ftmatrix, 0);
266 }
267
268 /*
269 * IntLoadSystemFonts
270 *
271 * Search the system font directory and adds each font found.
272 */
273
274 VOID FASTCALL
275 IntLoadSystemFonts(VOID)
276 {
277 OBJECT_ATTRIBUTES ObjectAttributes;
278 UNICODE_STRING Directory, FileName, TempString;
279 IO_STATUS_BLOCK Iosb;
280 HANDLE hDirectory;
281 BYTE *DirInfoBuffer;
282 PFILE_DIRECTORY_INFORMATION DirInfo;
283 BOOLEAN bRestartScan = TRUE;
284 NTSTATUS Status;
285 INT i;
286 static UNICODE_STRING SearchPatterns[] =
287 {
288 RTL_CONSTANT_STRING(L"*.ttf"),
289 RTL_CONSTANT_STRING(L"*.ttc"),
290 RTL_CONSTANT_STRING(L"*.otf"),
291 RTL_CONSTANT_STRING(L"*.otc"),
292 RTL_CONSTANT_STRING(L"*.fon"),
293 RTL_CONSTANT_STRING(L"*.fnt")
294 };
295
296 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
297
298 InitializeObjectAttributes(
299 &ObjectAttributes,
300 &Directory,
301 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
302 NULL,
303 NULL);
304
305 Status = ZwOpenFile(
306 &hDirectory,
307 SYNCHRONIZE | FILE_LIST_DIRECTORY,
308 &ObjectAttributes,
309 &Iosb,
310 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
311 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
312
313 if (NT_SUCCESS(Status))
314 {
315 for (i = 0; i < _countof(SearchPatterns); ++i)
316 {
317 DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
318 if (DirInfoBuffer == NULL)
319 {
320 ZwClose(hDirectory);
321 return;
322 }
323
324 FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
325 if (FileName.Buffer == NULL)
326 {
327 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
328 ZwClose(hDirectory);
329 return;
330 }
331 FileName.Length = 0;
332 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
333
334 while (1)
335 {
336 Status = ZwQueryDirectoryFile(
337 hDirectory,
338 NULL,
339 NULL,
340 NULL,
341 &Iosb,
342 DirInfoBuffer,
343 0x4000,
344 FileDirectoryInformation,
345 FALSE,
346 &SearchPatterns[i],
347 bRestartScan);
348
349 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
350 {
351 break;
352 }
353
354 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
355 while (1)
356 {
357 TempString.Buffer = DirInfo->FileName;
358 TempString.Length =
359 TempString.MaximumLength = DirInfo->FileNameLength;
360 RtlCopyUnicodeString(&FileName, &Directory);
361 RtlAppendUnicodeStringToString(&FileName, &TempString);
362 IntGdiAddFontResource(&FileName, 0);
363 if (DirInfo->NextEntryOffset == 0)
364 break;
365 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
366 }
367
368 bRestartScan = FALSE;
369 }
370
371 ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
372 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
373 }
374 ZwClose(hDirectory);
375 }
376 }
377
378 static BYTE
379 ItalicFromStyle(const char *style_name)
380 {
381 if (style_name == NULL || style_name[0] == 0)
382 return FALSE;
383 if (strstr(style_name, "Italic") != NULL)
384 return TRUE;
385 if (strstr(style_name, "Oblique") != NULL)
386 return TRUE;
387 return FALSE;
388 }
389
390 static LONG
391 WeightFromStyle(const char *style_name)
392 {
393 if (style_name == NULL || style_name[0] == 0)
394 return FW_NORMAL;
395 if (strstr(style_name, "Regular") != NULL)
396 return FW_REGULAR;
397 if (strstr(style_name, "Normal") != NULL)
398 return FW_NORMAL;
399 if (strstr(style_name, "SemiBold") != NULL)
400 return FW_SEMIBOLD;
401 if (strstr(style_name, "UltraBold") != NULL)
402 return FW_ULTRABOLD;
403 if (strstr(style_name, "DemiBold") != NULL)
404 return FW_DEMIBOLD;
405 if (strstr(style_name, "ExtraBold") != NULL)
406 return FW_EXTRABOLD;
407 if (strstr(style_name, "Bold") != NULL)
408 return FW_BOLD;
409 if (strstr(style_name, "UltraLight") != NULL)
410 return FW_ULTRALIGHT;
411 if (strstr(style_name, "ExtraLight") != NULL)
412 return FW_EXTRALIGHT;
413 if (strstr(style_name, "Light") != NULL)
414 return FW_LIGHT;
415 if (strstr(style_name, "Hairline") != NULL)
416 return 50;
417 if (strstr(style_name, "Book") != NULL)
418 return 350;
419 if (strstr(style_name, "ExtraBlack") != NULL)
420 return 950;
421 if (strstr(style_name, "UltraBlack") != NULL)
422 return 1000;
423 if (strstr(style_name, "Black") != NULL)
424 return FW_BLACK;
425 if (strstr(style_name, "Medium") != NULL)
426 return FW_MEDIUM;
427 if (strstr(style_name, "Thin") != NULL)
428 return FW_THIN;
429 if (strstr(style_name, "Heavy") != NULL)
430 return FW_HEAVY;
431 return FW_NORMAL;
432 }
433
434 typedef struct GDI_LOAD_FONT
435 {
436 PUNICODE_STRING pFileName;
437 PVOID Buffer;
438 ULONG BufferSize;
439 DWORD Characteristics;
440 UNICODE_STRING RegValueName;
441 BOOL IsTrueType;
442 } GDI_LOAD_FONT, *PGDI_LOAD_FONT;
443
444 static INT FASTCALL
445 IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
446 PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
447 {
448 FT_Error Error;
449 PFONT_ENTRY Entry;
450 FONTGDI * FontGDI;
451 NTSTATUS Status;
452 FT_Face Face;
453 ANSI_STRING AnsiFaceName;
454 FT_WinFNT_HeaderRec WinFNT;
455 INT FontCount = 0, CharSetCount = 0;
456 PUNICODE_STRING pFileName = pLoadFont->pFileName;
457 PVOID Buffer = pLoadFont->Buffer;
458 ULONG BufferSize = pLoadFont->BufferSize;
459 DWORD Characteristics = pLoadFont->Characteristics;
460 PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
461 TT_OS2 * pOS2;
462 INT BitIndex;
463 FT_UShort os2_version;
464 FT_ULong os2_ulCodePageRange1;
465 FT_UShort os2_usWeightClass;
466
467 if (SharedFace == NULL && CharSetIndex == -1)
468 {
469 /* load a face from memory */
470 IntLockFreeType;
471 Error = FT_New_Memory_Face(
472 library,
473 Buffer,
474 BufferSize,
475 ((FontIndex != -1) ? FontIndex : 0),
476 &Face);
477 IntUnLockFreeType;
478
479 if (FT_IS_SFNT(Face))
480 pLoadFont->IsTrueType = TRUE;
481
482 if (!Error)
483 SharedFace = SharedFace_Create(Face);
484 if (Error || SharedFace == NULL)
485 {
486 if (Error == FT_Err_Unknown_File_Format)
487 DPRINT1("Unknown font file format\n");
488 else
489 DPRINT1("Error reading font file (error code: %d)\n", Error);
490 return 0; /* failure */
491 }
492 }
493 else
494 {
495 Face = SharedFace->Face;
496 SharedFace_AddRef(SharedFace);
497 }
498
499 /* allocate a FONT_ENTRY */
500 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
501 if (!Entry)
502 {
503 SharedFace_Release(SharedFace);
504 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
505 return 0; /* failure */
506 }
507
508 /* allocate a FONTGDI */
509 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
510 if (!FontGDI)
511 {
512 SharedFace_Release(SharedFace);
513 ExFreePoolWithTag(Entry, TAG_FONT);
514 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
515 return 0; /* failure */
516 }
517
518 /* set file name */
519 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool,
520 pFileName->Length + sizeof(UNICODE_NULL),
521 GDITAG_PFF);
522 if (FontGDI->Filename == NULL)
523 {
524 EngFreeMem(FontGDI);
525 SharedFace_Release(SharedFace);
526 ExFreePoolWithTag(Entry, TAG_FONT);
527 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
528 return 0; /* failure */
529 }
530 RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
531 FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
532
533 /* set face */
534 FontGDI->SharedFace = SharedFace;
535 FontGDI->CharSet = ANSI_CHARSET;
536 FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name);
537 FontGDI->RequestItalic = FALSE;
538 FontGDI->OriginalWeight = WeightFromStyle(Face->style_name);
539 FontGDI->RequestWeight = FW_NORMAL;
540
541 RtlInitAnsiString(&AnsiFaceName, Face->family_name);
542 Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
543 if (!NT_SUCCESS(Status))
544 {
545 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
546 EngFreeMem(FontGDI);
547 SharedFace_Release(SharedFace);
548 ExFreePoolWithTag(Entry, TAG_FONT);
549 return 0;
550 }
551
552 os2_version = 0;
553 IntLockFreeType;
554 pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
555 if (pOS2)
556 {
557 os2_version = pOS2->version;
558 os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
559 os2_usWeightClass = pOS2->usWeightClass;
560 }
561 IntUnLockFreeType;
562
563 if (pOS2 && os2_version >= 1)
564 {
565 /* get charset and weight from OS/2 header */
566
567 /* Make sure we do not use this pointer anymore */
568 pOS2 = NULL;
569
570 for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
571 {
572 if (os2_ulCodePageRange1 & (1 << BitIndex))
573 {
574 if (FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
575 continue;
576
577 if ((CharSetIndex == -1 && CharSetCount == 0) ||
578 CharSetIndex == CharSetCount)
579 {
580 FontGDI->CharSet = FontTci[BitIndex].ciCharset;
581 }
582
583 ++CharSetCount;
584 }
585 }
586
587 /* set actual weight */
588 FontGDI->OriginalWeight = os2_usWeightClass;
589 }
590 else
591 {
592 /* get charset from WinFNT header */
593 IntLockFreeType;
594 Error = FT_Get_WinFNT_Header(Face, &WinFNT);
595 if (!Error)
596 {
597 FontGDI->CharSet = WinFNT.charset;
598 }
599 IntUnLockFreeType;
600 }
601
602 /* FIXME: CharSet is invalid on Marlett */
603 if (RtlEqualUnicodeString(&Entry->FaceName, &MarlettW, TRUE))
604 {
605 FontGDI->CharSet = SYMBOL_CHARSET;
606 }
607
608 ++FontCount;
609 DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
610 DPRINT("Num glyphs: %d\n", Face->num_glyphs);
611 DPRINT("CharSet: %d\n", FontGDI->CharSet);
612
613 /* Add this font resource to the font table */
614 Entry->Font = FontGDI;
615 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
616
617 if (Characteristics & FR_PRIVATE)
618 {
619 /* private font */
620 PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
621 IntLockProcessPrivateFonts(Win32Process);
622 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
623 IntUnLockProcessPrivateFonts(Win32Process);
624 }
625 else
626 {
627 /* global font */
628 IntLockGlobalFonts;
629 InsertTailList(&FontListHead, &Entry->ListEntry);
630 IntUnLockGlobalFonts;
631 }
632
633 if (FontIndex == -1)
634 {
635 if (FT_IS_SFNT(Face))
636 {
637 TT_Face TrueType = (TT_Face)Face;
638 if (TrueType->ttc_header.count > 1)
639 {
640 FT_Long i;
641 for (i = 1; i < TrueType->ttc_header.count; ++i)
642 {
643 FontCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
644 }
645 }
646 }
647 FontIndex = 0;
648 }
649
650 if (CharSetIndex == -1)
651 {
652 INT i;
653
654 if (pLoadFont->RegValueName.Length == 0)
655 {
656 RtlCreateUnicodeString(pValueName, Entry->FaceName.Buffer);
657 }
658 else
659 {
660 UNICODE_STRING NewString;
661 USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + Entry->FaceName.Length;
662 NewString.Length = 0;
663 NewString.MaximumLength = Length + sizeof(WCHAR);
664 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
665 NewString.MaximumLength,
666 TAG_USTR);
667 NewString.Buffer[0] = UNICODE_NULL;
668
669 RtlAppendUnicodeStringToString(&NewString, pValueName);
670 RtlAppendUnicodeToString(&NewString, L" & ");
671 RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
672
673 RtlFreeUnicodeString(pValueName);
674 *pValueName = NewString;
675 }
676
677 for (i = 1; i < CharSetCount; ++i)
678 {
679 FontCount += IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
680 }
681 }
682
683 return FontCount; /* number of loaded fonts */
684 }
685
686 /*
687 * IntGdiAddFontResource
688 *
689 * Adds the font resource from the specified file to the system.
690 */
691
692 INT FASTCALL
693 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
694 {
695 NTSTATUS Status;
696 HANDLE FileHandle;
697 PVOID Buffer = NULL;
698 IO_STATUS_BLOCK Iosb;
699 PVOID SectionObject;
700 ULONG ViewSize = 0;
701 LARGE_INTEGER SectionSize;
702 OBJECT_ATTRIBUTES ObjectAttributes;
703 GDI_LOAD_FONT LoadFont;
704 INT FontCount;
705 HANDLE KeyHandle;
706 static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
707
708 /* Open the font file */
709 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
710 Status = ZwOpenFile(
711 &FileHandle,
712 FILE_GENERIC_READ | SYNCHRONIZE,
713 &ObjectAttributes,
714 &Iosb,
715 FILE_SHARE_READ,
716 FILE_SYNCHRONOUS_IO_NONALERT);
717 if (!NT_SUCCESS(Status))
718 {
719 DPRINT("Could not load font file: %wZ\n", FileName);
720 return 0;
721 }
722
723 SectionSize.QuadPart = 0LL;
724 Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
725 NULL, &SectionSize, PAGE_READONLY,
726 SEC_COMMIT, FileHandle, NULL);
727 if (!NT_SUCCESS(Status))
728 {
729 DPRINT("Could not map file: %wZ\n", FileName);
730 ZwClose(FileHandle);
731 return 0;
732 }
733 ZwClose(FileHandle);
734
735 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
736 if (!NT_SUCCESS(Status))
737 {
738 DPRINT("Could not map file: %wZ\n", FileName);
739 ObDereferenceObject(SectionObject);
740 return 0;
741 }
742
743 LoadFont.pFileName = FileName;
744 LoadFont.Buffer = Buffer;
745 LoadFont.BufferSize = ViewSize;
746 LoadFont.Characteristics = Characteristics;
747 RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
748 LoadFont.IsTrueType = FALSE;
749 FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
750
751 ObDereferenceObject(SectionObject);
752
753 if (FontCount > 0)
754 {
755 if (LoadFont.IsTrueType)
756 {
757 /* append " (TrueType)" */
758 UNICODE_STRING NewString;
759 USHORT Length;
760
761 Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length;
762 NewString.Length = 0;
763 NewString.MaximumLength = Length + sizeof(WCHAR);
764 NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
765 NewString.MaximumLength,
766 TAG_USTR);
767 NewString.Buffer[0] = UNICODE_NULL;
768
769 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
770 RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
771 RtlFreeUnicodeString(&LoadFont.RegValueName);
772 LoadFont.RegValueName = NewString;
773 }
774
775 /* registry */
776 InitializeObjectAttributes(&ObjectAttributes, &FontRegPath,
777 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
778 NULL, NULL);
779 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
780 if (NT_SUCCESS(Status))
781 {
782 ULONG DataSize;
783 LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
784 if (pFileName)
785 {
786 pFileName++;
787 DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
788 ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
789 pFileName, DataSize);
790 }
791 ZwClose(KeyHandle);
792 }
793 }
794 RtlFreeUnicodeString(&LoadFont.RegValueName);
795
796 return FontCount;
797 }
798
799 // FIXME: Add RemoveFontResource
800
801 BOOL FASTCALL
802 IntIsFontRenderingEnabled(VOID)
803 {
804 BOOL Ret = RenderingEnabled;
805 HDC hDC;
806
807 hDC = IntGetScreenDC();
808 if (hDC)
809 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
810
811 return Ret;
812 }
813
814 VOID FASTCALL
815 IntEnableFontRendering(BOOL Enable)
816 {
817 RenderingEnabled = Enable;
818 }
819
820 FT_Render_Mode FASTCALL
821 IntGetFontRenderMode(LOGFONTW *logfont)
822 {
823 switch (logfont->lfQuality)
824 {
825 case ANTIALIASED_QUALITY:
826 case NONANTIALIASED_QUALITY:
827 return FT_RENDER_MODE_MONO;
828 case DRAFT_QUALITY:
829 return FT_RENDER_MODE_LIGHT;
830 /* case CLEARTYPE_QUALITY:
831 return FT_RENDER_MODE_LCD; */
832 }
833 return FT_RENDER_MODE_NORMAL;
834 }
835
836
837 NTSTATUS FASTCALL
838 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
839 {
840 PLFONT plfont;
841 LOGFONTW *plf;
842
843 plfont = LFONT_AllocFontWithHandle();
844 if (!plfont)
845 {
846 return STATUS_NO_MEMORY;
847 }
848
849 ExInitializePushLock(&plfont->lock);
850 *NewFont = plfont->BaseObject.hHmgr;
851 plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
852 RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
853 if (lf->lfEscapement != lf->lfOrientation)
854 {
855 /* This should really depend on whether GM_ADVANCED is set */
856 plf->lfOrientation = plf->lfEscapement;
857 }
858 LFONT_UnlockFont(plfont);
859
860 return STATUS_SUCCESS;
861 }
862
863 /*************************************************************************
864 * TranslateCharsetInfo
865 *
866 * Fills a CHARSETINFO structure for a character set, code page, or
867 * font. This allows making the correspondance between different labelings
868 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
869 * of the same encoding.
870 *
871 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
872 * only one codepage should be set in *Src.
873 *
874 * RETURNS
875 * TRUE on success, FALSE on failure.
876 *
877 */
878 static BOOLEAN APIENTRY
879 IntTranslateCharsetInfo(PDWORD Src, /* [in]
880 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
881 if flags == TCI_SRCCHARSET: a character set value
882 if flags == TCI_SRCCODEPAGE: a code page value */
883 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
884 DWORD Flags /* [in] determines interpretation of lpSrc */)
885 {
886 int Index = 0;
887
888 switch (Flags)
889 {
890 case TCI_SRCFONTSIG:
891 while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
892 {
893 Index++;
894 }
895 break;
896 case TCI_SRCCODEPAGE:
897 while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciACP)
898 {
899 Index++;
900 }
901 break;
902 case TCI_SRCCHARSET:
903 while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciCharset)
904 {
905 Index++;
906 }
907 break;
908 default:
909 return FALSE;
910 }
911
912 if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == FontTci[Index].ciCharset)
913 {
914 return FALSE;
915 }
916
917 RtlCopyMemory(Cs, &FontTci[Index], sizeof(CHARSETINFO));
918
919 return TRUE;
920 }
921
922
923 static BOOL face_has_symbol_charmap(FT_Face ft_face)
924 {
925 int i;
926
927 for(i = 0; i < ft_face->num_charmaps; i++)
928 {
929 if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
930 return TRUE;
931 }
932 return FALSE;
933 }
934
935
936 static void FASTCALL
937 FillTMEx(TEXTMETRICW *TM, PFONTGDI FontGDI,
938 TT_OS2 *pOS2, TT_HoriHeader *pHori,
939 FT_WinFNT_HeaderRec *pFNT, BOOL RealFont)
940 {
941 FT_Fixed XScale, YScale;
942 int Ascent, Descent;
943 FT_Face Face = FontGDI->SharedFace->Face;
944
945 XScale = Face->size->metrics.x_scale;
946 YScale = Face->size->metrics.y_scale;
947
948 if (pFNT)
949 {
950 TM->tmHeight = pFNT->pixel_height;
951 TM->tmAscent = pFNT->ascent;
952 TM->tmDescent = TM->tmHeight - TM->tmAscent;
953 TM->tmInternalLeading = pFNT->internal_leading;
954 TM->tmExternalLeading = pFNT->external_leading;
955 TM->tmAveCharWidth = pFNT->avg_width;
956 TM->tmMaxCharWidth = pFNT->max_width;
957 TM->tmOverhang = 0;
958 TM->tmDigitizedAspectX = pFNT->horizontal_resolution;
959 TM->tmDigitizedAspectY = pFNT->vertical_resolution;
960 TM->tmFirstChar = pFNT->first_char;
961 TM->tmLastChar = pFNT->last_char;
962 TM->tmDefaultChar = pFNT->default_char + pFNT->first_char;
963 TM->tmBreakChar = pFNT->break_char + pFNT->first_char;
964 TM->tmPitchAndFamily = pFNT->pitch_and_family;
965 if (RealFont)
966 {
967 TM->tmWeight = FontGDI->OriginalWeight;
968 TM->tmItalic = FontGDI->OriginalItalic;
969 TM->tmUnderlined = pFNT->underline;
970 TM->tmStruckOut = pFNT->strike_out;
971 TM->tmCharSet = pFNT->charset;
972 }
973 else
974 {
975 TM->tmWeight = FontGDI->RequestWeight;
976 TM->tmItalic = FontGDI->RequestItalic;
977 TM->tmUnderlined = FontGDI->RequestUnderline;
978 TM->tmStruckOut = FontGDI->RequestStrikeOut;
979 TM->tmCharSet = FontGDI->CharSet;
980 }
981 return;
982 }
983
984 if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
985 {
986 Ascent = pHori->Ascender;
987 Descent = -pHori->Descender;
988 }
989 else
990 {
991 Ascent = pOS2->usWinAscent;
992 Descent = pOS2->usWinDescent;
993 }
994
995 #if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */
996 TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
997 TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
998 #else /* This (ros) code was previously affected by a FreeType bug, but it works now */
999 TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* Units above baseline */
1000 TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* Units below baseline */
1001 #endif
1002 TM->tmInternalLeading = (FT_MulFix(Ascent + Descent - Face->units_per_EM, YScale) + 32) >> 6;
1003
1004 TM->tmHeight = TM->tmAscent + TM->tmDescent;
1005
1006 /* MSDN says:
1007 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
1008 */
1009 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
1010 - ((Ascent + Descent)
1011 - (pHori->Ascender - pHori->Descender)),
1012 YScale) + 32) >> 6);
1013
1014 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
1015 if (TM->tmAveCharWidth == 0)
1016 {
1017 TM->tmAveCharWidth = 1;
1018 }
1019
1020 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
1021 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
1022
1023 if (RealFont)
1024 {
1025 TM->tmWeight = FontGDI->OriginalWeight;
1026 }
1027 else
1028 {
1029 if (FontGDI->OriginalWeight != FW_DONTCARE &&
1030 FontGDI->OriginalWeight != FW_NORMAL)
1031 {
1032 TM->tmWeight = FontGDI->OriginalWeight;
1033 }
1034 else
1035 {
1036 TM->tmWeight = FontGDI->RequestWeight;
1037 }
1038 }
1039
1040 TM->tmOverhang = 0;
1041 TM->tmDigitizedAspectX = 96;
1042 TM->tmDigitizedAspectY = 96;
1043 if (face_has_symbol_charmap(Face) ||
1044 (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
1045 {
1046 USHORT cpOEM, cpAnsi;
1047
1048 EngGetCurrentCodePage(&cpOEM, &cpAnsi);
1049 TM->tmFirstChar = 0;
1050 switch(cpAnsi)
1051 {
1052 case 1257: /* Baltic */
1053 TM->tmLastChar = 0xf8fd;
1054 break;
1055 default:
1056 TM->tmLastChar = 0xf0ff;
1057 }
1058 TM->tmBreakChar = 0x20;
1059 TM->tmDefaultChar = 0x1f;
1060 }
1061 else
1062 {
1063 TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
1064 TM->tmLastChar = pOS2->usLastCharIndex; /* Should be min(cmap_last, os2_last) */
1065
1066 if(pOS2->usFirstCharIndex <= 1)
1067 TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
1068 else if (pOS2->usFirstCharIndex > 0xff)
1069 TM->tmBreakChar = 0x20;
1070 else
1071 TM->tmBreakChar = pOS2->usFirstCharIndex;
1072 TM->tmDefaultChar = TM->tmBreakChar - 1;
1073 }
1074
1075 if (RealFont)
1076 {
1077 TM->tmItalic = FontGDI->OriginalItalic;
1078 TM->tmUnderlined = FALSE;
1079 TM->tmStruckOut = FALSE;
1080 }
1081 else
1082 {
1083 if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
1084 {
1085 TM->tmItalic = 0xFF;
1086 }
1087 else
1088 {
1089 TM->tmItalic = 0;
1090 }
1091 TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
1092 TM->tmStruckOut = (FontGDI->RequestStrikeOut ? 0xFF : 0);
1093 }
1094
1095 if (!FT_IS_FIXED_WIDTH(Face))
1096 {
1097 TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH;
1098 }
1099 else
1100 {
1101 TM->tmPitchAndFamily = 0;
1102 }
1103
1104 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
1105 {
1106 case PAN_FAMILY_SCRIPT:
1107 TM->tmPitchAndFamily |= FF_SCRIPT;
1108 break;
1109 case PAN_FAMILY_DECORATIVE:
1110 TM->tmPitchAndFamily |= FF_DECORATIVE;
1111 break;
1112
1113 case PAN_ANY:
1114 case PAN_NO_FIT:
1115 case PAN_FAMILY_TEXT_DISPLAY:
1116 case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
1117 /* Which is clearly not what the panose spec says. */
1118 if (TM->tmPitchAndFamily == 0) /* Fixed */
1119 {
1120 TM->tmPitchAndFamily = FF_MODERN;
1121 }
1122 else
1123 {
1124 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
1125 {
1126 case PAN_ANY:
1127 case PAN_NO_FIT:
1128 default:
1129 TM->tmPitchAndFamily |= FF_DONTCARE;
1130 break;
1131
1132 case PAN_SERIF_COVE:
1133 case PAN_SERIF_OBTUSE_COVE:
1134 case PAN_SERIF_SQUARE_COVE:
1135 case PAN_SERIF_OBTUSE_SQUARE_COVE:
1136 case PAN_SERIF_SQUARE:
1137 case PAN_SERIF_THIN:
1138 case PAN_SERIF_BONE:
1139 case PAN_SERIF_EXAGGERATED:
1140 case PAN_SERIF_TRIANGLE:
1141 TM->tmPitchAndFamily |= FF_ROMAN;
1142 break;
1143
1144 case PAN_SERIF_NORMAL_SANS:
1145 case PAN_SERIF_OBTUSE_SANS:
1146 case PAN_SERIF_PERP_SANS:
1147 case PAN_SERIF_FLARED:
1148 case PAN_SERIF_ROUNDED:
1149 TM->tmPitchAndFamily |= FF_SWISS;
1150 break;
1151 }
1152 }
1153 break;
1154 default:
1155 TM->tmPitchAndFamily |= FF_DONTCARE;
1156 }
1157
1158 if (FT_IS_SCALABLE(Face))
1159 {
1160 TM->tmPitchAndFamily |= TMPF_VECTOR;
1161 }
1162 if (FT_IS_SFNT(Face))
1163 {
1164 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
1165 }
1166
1167 TM->tmCharSet = FontGDI->CharSet;
1168 }
1169
1170 static void FASTCALL
1171 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
1172 TT_OS2 *pOS2, TT_HoriHeader *pHori,
1173 FT_WinFNT_HeaderRec *pFNT)
1174 {
1175 FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
1176 }
1177
1178 /*************************************************************
1179 * IntGetOutlineTextMetrics
1180 *
1181 */
1182 INT FASTCALL
1183 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
1184 UINT Size,
1185 OUTLINETEXTMETRICW *Otm)
1186 {
1187 unsigned Needed;
1188 TT_OS2 *pOS2;
1189 TT_HoriHeader *pHori;
1190 TT_Postscript *pPost;
1191 FT_Fixed XScale, YScale;
1192 ANSI_STRING FamilyNameA, StyleNameA;
1193 UNICODE_STRING FamilyNameW, StyleNameW, Regular;
1194 FT_WinFNT_HeaderRec Win;
1195 FT_Error Error;
1196 char *Cp;
1197 NTSTATUS status;
1198 FT_Face Face = FontGDI->SharedFace->Face;
1199
1200 Needed = sizeof(OUTLINETEXTMETRICW);
1201
1202 RtlInitAnsiString(&FamilyNameA, Face->family_name);
1203 status = RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
1204 if (!NT_SUCCESS(status))
1205 {
1206 return 0;
1207 }
1208
1209 RtlInitAnsiString(&StyleNameA, Face->style_name);
1210 status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
1211 if (!NT_SUCCESS(status))
1212 {
1213 RtlFreeUnicodeString(&FamilyNameW);
1214 return 0;
1215 }
1216
1217 /* These names should be read from the TT name table */
1218
1219 /* Length of otmpFamilyName */
1220 Needed += FamilyNameW.Length + sizeof(WCHAR);
1221
1222 RtlInitUnicodeString(&Regular, L"Regular");
1223 /* Length of otmpFaceName */
1224 if (RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
1225 {
1226 Needed += FamilyNameW.Length + sizeof(WCHAR); /* Just the family name */
1227 }
1228 else
1229 {
1230 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
1231 }
1232
1233 /* Length of otmpStyleName */
1234 Needed += StyleNameW.Length + sizeof(WCHAR);
1235
1236 /* Length of otmpFullName */
1237 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
1238
1239 if (Size < Needed)
1240 {
1241 RtlFreeUnicodeString(&FamilyNameW);
1242 RtlFreeUnicodeString(&StyleNameW);
1243 return Needed;
1244 }
1245
1246 XScale = Face->size->metrics.x_scale;
1247 YScale = Face->size->metrics.y_scale;
1248
1249 IntLockFreeType;
1250 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
1251 if (NULL == pOS2)
1252 {
1253 IntUnLockFreeType;
1254 DPRINT1("Can't find OS/2 table - not TT font?\n");
1255 RtlFreeUnicodeString(&StyleNameW);
1256 RtlFreeUnicodeString(&FamilyNameW);
1257 return 0;
1258 }
1259
1260 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
1261 if (NULL == pHori)
1262 {
1263 IntUnLockFreeType;
1264 DPRINT1("Can't find HHEA table - not TT font?\n");
1265 RtlFreeUnicodeString(&StyleNameW);
1266 RtlFreeUnicodeString(&FamilyNameW);
1267 return 0;
1268 }
1269
1270 pPost = FT_Get_Sfnt_Table(Face, ft_sfnt_post); /* We can live with this failing */
1271
1272 Error = FT_Get_WinFNT_Header(Face , &Win);
1273
1274 Otm->otmSize = Needed;
1275
1276 FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
1277
1278 Otm->otmFiller = 0;
1279 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
1280 Otm->otmfsSelection = pOS2->fsSelection;
1281 Otm->otmfsType = pOS2->fsType;
1282 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
1283 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
1284 Otm->otmItalicAngle = 0; /* POST table */
1285 Otm->otmEMSquare = Face->units_per_EM;
1286 Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
1287 Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
1288 Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
1289 Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
1290 Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
1291 Otm->otmrcFontBox.left = (FT_MulFix(Face->bbox.xMin, XScale) + 32) >> 6;
1292 Otm->otmrcFontBox.right = (FT_MulFix(Face->bbox.xMax, XScale) + 32) >> 6;
1293 Otm->otmrcFontBox.top = (FT_MulFix(Face->bbox.yMax, YScale) + 32) >> 6;
1294 Otm->otmrcFontBox.bottom = (FT_MulFix(Face->bbox.yMin, YScale) + 32) >> 6;
1295 Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
1296 Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
1297 Otm->otmMacLineGap = Otm->otmLineGap;
1298 Otm->otmusMinimumPPEM = 0; /* TT Header */
1299 Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
1300 Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
1301 Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
1302 Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
1303 Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
1304 Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
1305 Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
1306 Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
1307 Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
1308 Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
1309 if (!pPost)
1310 {
1311 Otm->otmsUnderscoreSize = 0;
1312 Otm->otmsUnderscorePosition = 0;
1313 }
1314 else
1315 {
1316 Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
1317 Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
1318 }
1319
1320 IntUnLockFreeType;
1321
1322 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
1323 Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
1324 Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
1325 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1326 Cp += FamilyNameW.Length + sizeof(WCHAR);
1327 Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
1328 wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
1329 Cp += StyleNameW.Length + sizeof(WCHAR);
1330 Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
1331 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1332 if (!RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
1333 {
1334 wcscat((WCHAR*) Cp, L" ");
1335 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
1336 Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
1337 }
1338 else
1339 {
1340 Cp += FamilyNameW.Length + sizeof(WCHAR);
1341 }
1342 Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
1343 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
1344 wcscat((WCHAR*) Cp, L" ");
1345 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
1346
1347 RtlFreeUnicodeString(&StyleNameW);
1348 RtlFreeUnicodeString(&FamilyNameW);
1349
1350 return Needed;
1351 }
1352
1353 static PFONTGDI FASTCALL
1354 FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
1355 {
1356 PLIST_ENTRY Entry;
1357 PFONT_ENTRY CurrentEntry;
1358 ANSI_STRING EntryFaceNameA;
1359 UNICODE_STRING EntryFaceNameW;
1360 FONTGDI *FontGDI;
1361 NTSTATUS status;
1362
1363 Entry = Head->Flink;
1364 while (Entry != Head)
1365 {
1366 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1367
1368 FontGDI = CurrentEntry->Font;
1369 ASSERT(FontGDI);
1370
1371 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
1372 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
1373 if (!NT_SUCCESS(status))
1374 {
1375 break;
1376 }
1377
1378 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
1379 {
1380 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
1381 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
1382 }
1383
1384 if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE))
1385 {
1386 RtlFreeUnicodeString(&EntryFaceNameW);
1387 return FontGDI;
1388 }
1389
1390 RtlFreeUnicodeString(&EntryFaceNameW);
1391 Entry = Entry->Flink;
1392 }
1393
1394 return NULL;
1395 }
1396
1397 static PFONTGDI FASTCALL
1398 FindFaceNameInLists(PUNICODE_STRING FaceName)
1399 {
1400 PPROCESSINFO Win32Process;
1401 PFONTGDI Font;
1402
1403 /* Search the process local list */
1404 Win32Process = PsGetCurrentProcessWin32Process();
1405 IntLockProcessPrivateFonts(Win32Process);
1406 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
1407 IntUnLockProcessPrivateFonts(Win32Process);
1408 if (NULL != Font)
1409 {
1410 return Font;
1411 }
1412
1413 /* Search the global list */
1414 IntLockGlobalFonts;
1415 Font = FindFaceNameInList(FaceName, &FontListHead);
1416 IntUnLockGlobalFonts;
1417
1418 return Font;
1419 }
1420
1421 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
1422 static BYTE
1423 CharSetFromLangID(LANGID LangID)
1424 {
1425 /* FIXME: Add more and fix if wrong */
1426 switch (PRIMARYLANGID(LangID))
1427 {
1428 case LANG_CHINESE:
1429 switch (SUBLANGID(LangID))
1430 {
1431 case SUBLANG_CHINESE_TRADITIONAL:
1432 return CHINESEBIG5_CHARSET;
1433 case SUBLANG_CHINESE_SIMPLIFIED:
1434 default:
1435 break;
1436 }
1437 return GB2312_CHARSET;
1438
1439 case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
1440 case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
1441 return EASTEUROPE_CHARSET;
1442
1443 case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
1444 case LANG_SERBIAN: case LANG_UKRAINIAN:
1445 return RUSSIAN_CHARSET;
1446
1447 case LANG_ARABIC: return ARABIC_CHARSET;
1448 case LANG_GREEK: return GREEK_CHARSET;
1449 case LANG_HEBREW: return HEBREW_CHARSET;
1450 case LANG_JAPANESE: return SHIFTJIS_CHARSET;
1451 case LANG_KOREAN: return JOHAB_CHARSET;
1452 case LANG_TURKISH: return TURKISH_CHARSET;
1453 case LANG_THAI: return THAI_CHARSET;
1454 case LANG_LATVIAN: return BALTIC_CHARSET;
1455 case LANG_VIETNAMESE: return VIETNAMESE_CHARSET;
1456
1457 case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
1458 case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
1459 case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
1460 case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
1461 case LANG_SWEDISH: default:
1462 return ANSI_CHARSET;
1463 }
1464 }
1465
1466 static void
1467 SwapEndian(LPVOID pvData, DWORD Size)
1468 {
1469 BYTE b, *pb = pvData;
1470 Size /= 2;
1471 while (Size-- > 0)
1472 {
1473 b = pb[0];
1474 pb[0] = pb[1];
1475 pb[1] = b;
1476 ++pb; ++pb;
1477 }
1478 }
1479
1480 static NTSTATUS
1481 IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face)
1482 {
1483 FT_SfntName Name;
1484 INT i, Count;
1485 WCHAR Buf[LF_FACESIZE];
1486 NTSTATUS Status = STATUS_NOT_FOUND;
1487
1488 RtlInitUnicodeString(pLocalNameW, NULL);
1489
1490 Count = FT_Get_Sfnt_Name_Count(Face);
1491 for (i = 0; i < Count; ++i)
1492 {
1493 FT_Get_Sfnt_Name(Face, i, &Name);
1494 if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
1495 Name.encoding_id != TT_MS_ID_UNICODE_CS)
1496 {
1497 continue; /* not Microsoft Unicode name */
1498 }
1499
1500 if (Name.name_id != TT_NAME_ID_FONT_FAMILY ||
1501 Name.string == NULL || Name.string_len == 0 ||
1502 (Name.string[0] == 0 && Name.string[1] == 0))
1503 {
1504 continue; /* not family name */
1505 }
1506
1507 if (sizeof(Buf) < Name.string_len + sizeof(UNICODE_NULL))
1508 {
1509 continue; /* name too long */
1510 }
1511
1512 /* NOTE: Name.string is not null-terminated */
1513 RtlCopyMemory(Buf, Name.string, Name.string_len);
1514 Buf[Name.string_len / sizeof(WCHAR)] = UNICODE_NULL;
1515
1516 /* Convert UTF-16 big endian to little endian */
1517 SwapEndian(Buf, Name.string_len);
1518 #if 0
1519 DPRINT("IntGetFontLocalizedName: %S (%d)\n", Buf, Name.string_len);
1520 #endif
1521
1522 Status = RtlCreateUnicodeString(pLocalNameW, Buf);
1523 break;
1524 }
1525
1526 return Status;
1527 }
1528
1529 static void FASTCALL
1530 FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
1531 {
1532 ANSI_STRING StyleA;
1533 UNICODE_STRING StyleW;
1534 TT_OS2 *pOS2;
1535 FONTSIGNATURE fs;
1536 CHARSETINFO CharSetInfo;
1537 unsigned i, Size;
1538 OUTLINETEXTMETRICW *Otm;
1539 LOGFONTW *Lf;
1540 TEXTMETRICW *TM;
1541 NEWTEXTMETRICW *Ntm;
1542 DWORD fs0;
1543 NTSTATUS status;
1544 FT_Face Face = FontGDI->SharedFace->Face;
1545
1546 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
1547 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
1548 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
1549 if (!Otm)
1550 {
1551 return;
1552 }
1553 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
1554
1555 Lf = &Info->EnumLogFontEx.elfLogFont;
1556 TM = &Otm->otmTextMetrics;
1557
1558 Lf->lfHeight = TM->tmHeight;
1559 Lf->lfWidth = TM->tmAveCharWidth;
1560 Lf->lfWeight = TM->tmWeight;
1561 Lf->lfItalic = TM->tmItalic;
1562 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
1563 Lf->lfCharSet = TM->tmCharSet;
1564 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
1565 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
1566 Lf->lfQuality = PROOF_QUALITY;
1567
1568 Ntm = &Info->NewTextMetricEx.ntmTm;
1569 Ntm->tmHeight = TM->tmHeight;
1570 Ntm->tmAscent = TM->tmAscent;
1571 Ntm->tmDescent = TM->tmDescent;
1572 Ntm->tmInternalLeading = TM->tmInternalLeading;
1573 Ntm->tmExternalLeading = TM->tmExternalLeading;
1574 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
1575 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
1576 Ntm->tmWeight = TM->tmWeight;
1577 Ntm->tmOverhang = TM->tmOverhang;
1578 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
1579 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
1580 Ntm->tmFirstChar = TM->tmFirstChar;
1581 Ntm->tmLastChar = TM->tmLastChar;
1582 Ntm->tmDefaultChar = TM->tmDefaultChar;
1583 Ntm->tmBreakChar = TM->tmBreakChar;
1584 Ntm->tmItalic = TM->tmItalic;
1585 Ntm->tmUnderlined = TM->tmUnderlined;
1586 Ntm->tmStruckOut = TM->tmStruckOut;
1587 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
1588 Ntm->tmCharSet = TM->tmCharSet;
1589 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
1590
1591 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
1592
1593 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
1594
1595 Ntm->ntmSizeEM = Otm->otmEMSquare;
1596 Ntm->ntmCellHeight = Otm->otmEMSquare;
1597 Ntm->ntmAvgWidth = 0;
1598
1599 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
1600 ? TRUETYPE_FONTTYPE : 0);
1601
1602 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
1603 Info->FontType |= RASTER_FONTTYPE;
1604
1605 ExFreePoolWithTag(Otm, GDITAG_TEXT);
1606
1607 /* try the localized name */
1608 status = STATUS_UNSUCCESSFUL;
1609 if (CharSetFromLangID(gusLanguageID) == FontGDI->CharSet)
1610 {
1611 /* get localized name */
1612 UNICODE_STRING LocalNameW;
1613 status = IntGetFontLocalizedName(&LocalNameW, Face);
1614 if (NT_SUCCESS(status))
1615 {
1616 /* store it */
1617 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
1618 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
1619 LocalNameW.Buffer);
1620 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
1621 sizeof(Info->EnumLogFontEx.elfFullName),
1622 LocalNameW.Buffer);
1623 }
1624 RtlFreeUnicodeString(&LocalNameW);
1625 }
1626
1627 /* if localized name was unavailable */
1628 if (!NT_SUCCESS(status))
1629 {
1630 /* store English name */
1631 RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
1632 sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
1633 FaceName);
1634 RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
1635 sizeof(Info->EnumLogFontEx.elfFullName),
1636 FaceName);
1637 }
1638
1639 RtlInitAnsiString(&StyleA, Face->style_name);
1640 StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
1641 StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
1642 status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
1643 if (!NT_SUCCESS(status))
1644 {
1645 return;
1646 }
1647 if (StyleW.Length)
1648 {
1649 if (wcslen(Info->EnumLogFontEx.elfFullName) +
1650 StyleW.Length / sizeof(WCHAR) + 1 <=
1651 sizeof(Info->EnumLogFontEx.elfFullName))
1652 {
1653 wcscat(Info->EnumLogFontEx.elfFullName, L" ");
1654 wcscat(Info->EnumLogFontEx.elfFullName, StyleW.Buffer);
1655 }
1656 }
1657
1658 Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
1659 Info->EnumLogFontEx.elfScript[0] = L'\0';
1660 IntLockFreeType;
1661 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
1662
1663 if (!pOS2)
1664 {
1665 IntUnLockFreeType;
1666 return;
1667 }
1668
1669 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1670 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1671 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1672 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1673 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1674 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1675
1676 if (0 == pOS2->version)
1677 {
1678 FT_UInt Dummy;
1679
1680 if (FT_Get_First_Char(Face, &Dummy) < 0x100)
1681 fs.fsCsb[0] |= FS_LATIN1;
1682 else
1683 fs.fsCsb[0] |= FS_SYMBOL;
1684 }
1685 IntUnLockFreeType;
1686
1687 if (fs.fsCsb[0] == 0)
1688 {
1689 /* Let's see if we can find any interesting cmaps */
1690 for (i = 0; i < (UINT)Face->num_charmaps; i++)
1691 {
1692 switch (Face->charmaps[i]->encoding)
1693 {
1694 case FT_ENCODING_UNICODE:
1695 case FT_ENCODING_APPLE_ROMAN:
1696 fs.fsCsb[0] |= FS_LATIN1;
1697 break;
1698 case FT_ENCODING_MS_SYMBOL:
1699 fs.fsCsb[0] |= FS_SYMBOL;
1700 break;
1701 default:
1702 break;
1703 }
1704 }
1705 }
1706
1707 for (i = 0; i < MAXTCIINDEX; i++)
1708 {
1709 fs0 = 1L << i;
1710 if (fs.fsCsb[0] & fs0)
1711 {
1712 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
1713 {
1714 CharSetInfo.ciCharset = DEFAULT_CHARSET;
1715 }
1716 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
1717 {
1718 Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
1719 if (ElfScripts[i])
1720 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
1721 else
1722 {
1723 DPRINT1("Unknown elfscript for bit %u\n", i);
1724 }
1725 }
1726 }
1727 }
1728 Info->NewTextMetricEx.ntmFontSig = fs;
1729 }
1730
1731 static int FASTCALL
1732 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
1733 {
1734 DWORD i;
1735 UNICODE_STRING InfoFaceName;
1736
1737 for (i = 0; i < InfoEntries; i++)
1738 {
1739 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
1740 if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE))
1741 {
1742 return i;
1743 }
1744 }
1745
1746 return -1;
1747 }
1748
1749 static BOOLEAN FASTCALL
1750 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
1751 PFONTFAMILYINFO Info, DWORD InfoEntries)
1752 {
1753 UNICODE_STRING LogFontFaceName;
1754
1755 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
1756 if (0 != LogFontFaceName.Length &&
1757 !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE))
1758 {
1759 return FALSE;
1760 }
1761
1762 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
1763 }
1764
1765 static BOOLEAN FASTCALL
1766 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
1767 PFONTFAMILYINFO Info,
1768 DWORD *Count,
1769 DWORD Size,
1770 PLIST_ENTRY Head)
1771 {
1772 PLIST_ENTRY Entry;
1773 PFONT_ENTRY CurrentEntry;
1774 ANSI_STRING EntryFaceNameA;
1775 UNICODE_STRING EntryFaceNameW;
1776 FONTGDI *FontGDI;
1777 NTSTATUS status;
1778
1779 Entry = Head->Flink;
1780 while (Entry != Head)
1781 {
1782 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1783
1784 FontGDI = CurrentEntry->Font;
1785 ASSERT(FontGDI);
1786
1787 RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
1788 status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
1789 if (!NT_SUCCESS(status))
1790 {
1791 return FALSE;
1792 }
1793
1794 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
1795 {
1796 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
1797 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
1798 }
1799
1800 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
1801 {
1802 if (*Count < Size)
1803 {
1804 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
1805 }
1806 (*Count)++;
1807 }
1808 RtlFreeUnicodeString(&EntryFaceNameW);
1809 Entry = Entry->Flink;
1810 }
1811
1812 return TRUE;
1813 }
1814
1815 typedef struct FontFamilyInfoCallbackContext
1816 {
1817 LPLOGFONTW LogFont;
1818 PFONTFAMILYINFO Info;
1819 DWORD Count;
1820 DWORD Size;
1821 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
1822
1823 _Function_class_(RTL_QUERY_REGISTRY_ROUTINE)
1824 static NTSTATUS APIENTRY
1825 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
1826 IN PVOID ValueData, IN ULONG ValueLength,
1827 IN PVOID Context, IN PVOID EntryContext)
1828 {
1829 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
1830 UNICODE_STRING RegistryName, RegistryValue;
1831 int Existing;
1832 PFONTGDI FontGDI;
1833
1834 if (REG_SZ != ValueType)
1835 {
1836 return STATUS_SUCCESS;
1837 }
1838 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
1839 RtlInitUnicodeString(&RegistryName, ValueName);
1840
1841 /* Do we need to include this font family? */
1842 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
1843 min(InfoContext->Count, InfoContext->Size)))
1844 {
1845 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
1846 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
1847 min(InfoContext->Count, InfoContext->Size));
1848 if (0 <= Existing)
1849 {
1850 /* We already have the information about the "real" font. Just copy it */
1851 if (InfoContext->Count < InfoContext->Size)
1852 {
1853 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
1854 RtlStringCbCopyNW(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
1855 sizeof(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName),
1856 RegistryName.Buffer,
1857 RegistryName.Length);
1858 }
1859 InfoContext->Count++;
1860 return STATUS_SUCCESS;
1861 }
1862
1863 /* Try to find information about the "real" font */
1864 FontGDI = FindFaceNameInLists(&RegistryValue);
1865 if (NULL == FontGDI)
1866 {
1867 /* "Real" font not found, discard this registry entry */
1868 return STATUS_SUCCESS;
1869 }
1870
1871 /* Return info about the "real" font but with the name of the alias */
1872 if (InfoContext->Count < InfoContext->Size)
1873 {
1874 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
1875 RegistryName.Buffer, FontGDI);
1876 }
1877 InfoContext->Count++;
1878 return STATUS_SUCCESS;
1879 }
1880
1881 return STATUS_SUCCESS;
1882 }
1883
1884 static BOOLEAN FASTCALL
1885 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
1886 PFONTFAMILYINFO Info,
1887 DWORD *Count,
1888 DWORD Size)
1889 {
1890 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
1891 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
1892 NTSTATUS Status;
1893
1894 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
1895 The real work is done in the registry callback function */
1896 Context.LogFont = LogFont;
1897 Context.Info = Info;
1898 Context.Count = *Count;
1899 Context.Size = Size;
1900
1901 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
1902 QueryTable[0].Flags = 0;
1903 QueryTable[0].Name = NULL;
1904 QueryTable[0].EntryContext = NULL;
1905 QueryTable[0].DefaultType = REG_NONE;
1906 QueryTable[0].DefaultData = NULL;
1907 QueryTable[0].DefaultLength = 0;
1908
1909 QueryTable[1].QueryRoutine = NULL;
1910 QueryTable[1].Name = NULL;
1911
1912 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
1913 L"FontSubstitutes",
1914 QueryTable,
1915 &Context,
1916 NULL);
1917 if (NT_SUCCESS(Status))
1918 {
1919 *Count = Context.Count;
1920 }
1921
1922 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
1923 }
1924
1925 BOOL
1926 FASTCALL
1927 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
1928 {
1929 if ( lprs )
1930 {
1931 lprs->nSize = sizeof(RASTERIZER_STATUS);
1932 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
1933 lprs->nLanguageID = gusLanguageID;
1934 return TRUE;
1935 }
1936 EngSetLastError(ERROR_INVALID_PARAMETER);
1937 return FALSE;
1938 }
1939
1940 static
1941 BOOL
1942 SameScaleMatrix(
1943 PMATRIX pmx1,
1944 PMATRIX pmx2)
1945 {
1946 return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) &&
1947 FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) &&
1948 FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) &&
1949 FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22));
1950 }
1951
1952 FT_BitmapGlyph APIENTRY
1953 ftGdiGlyphCacheGet(
1954 FT_Face Face,
1955 INT GlyphIndex,
1956 INT Height,
1957 PMATRIX pmx)
1958 {
1959 PLIST_ENTRY CurrentEntry;
1960 PFONT_CACHE_ENTRY FontEntry;
1961
1962 CurrentEntry = FontCacheListHead.Flink;
1963 while (CurrentEntry != &FontCacheListHead)
1964 {
1965 FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
1966 if ((FontEntry->Face == Face) &&
1967 (FontEntry->GlyphIndex == GlyphIndex) &&
1968 (FontEntry->Height == Height) &&
1969 (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
1970 break;
1971 CurrentEntry = CurrentEntry->Flink;
1972 }
1973
1974 if (CurrentEntry == &FontCacheListHead)
1975 {
1976 return NULL;
1977 }
1978
1979 RemoveEntryList(CurrentEntry);
1980 InsertHeadList(&FontCacheListHead, CurrentEntry);
1981 return FontEntry->BitmapGlyph;
1982 }
1983
1984 /* no cache */
1985 FT_BitmapGlyph APIENTRY
1986 ftGdiGlyphSet(
1987 FT_Face Face,
1988 FT_GlyphSlot GlyphSlot,
1989 FT_Render_Mode RenderMode)
1990 {
1991 FT_Glyph Glyph;
1992 INT error;
1993 FT_Bitmap AlignedBitmap;
1994 FT_BitmapGlyph BitmapGlyph;
1995
1996 error = FT_Get_Glyph(GlyphSlot, &Glyph);
1997 if (error)
1998 {
1999 DPRINT1("Failure getting glyph.\n");
2000 return NULL;
2001 }
2002
2003 error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
2004 if (error)
2005 {
2006 FT_Done_Glyph(Glyph);
2007 DPRINT1("Failure rendering glyph.\n");
2008 return NULL;
2009 }
2010
2011 BitmapGlyph = (FT_BitmapGlyph)Glyph;
2012 FT_Bitmap_New(&AlignedBitmap);
2013 if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2014 {
2015 DPRINT1("Conversion failed\n");
2016 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2017 return NULL;
2018 }
2019
2020 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2021 BitmapGlyph->bitmap = AlignedBitmap;
2022
2023 return BitmapGlyph;
2024 }
2025
2026 FT_BitmapGlyph APIENTRY
2027 ftGdiGlyphCacheSet(
2028 FT_Face Face,
2029 INT GlyphIndex,
2030 INT Height,
2031 PMATRIX pmx,
2032 FT_GlyphSlot GlyphSlot,
2033 FT_Render_Mode RenderMode)
2034 {
2035 FT_Glyph GlyphCopy;
2036 INT error;
2037 PFONT_CACHE_ENTRY NewEntry;
2038 FT_Bitmap AlignedBitmap;
2039 FT_BitmapGlyph BitmapGlyph;
2040
2041 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
2042 if (error)
2043 {
2044 DPRINT1("Failure caching glyph.\n");
2045 return NULL;
2046 };
2047
2048 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
2049 if (error)
2050 {
2051 FT_Done_Glyph(GlyphCopy);
2052 DPRINT1("Failure rendering glyph.\n");
2053 return NULL;
2054 };
2055
2056 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
2057 if (!NewEntry)
2058 {
2059 DPRINT1("Alloc failure caching glyph.\n");
2060 FT_Done_Glyph(GlyphCopy);
2061 return NULL;
2062 }
2063
2064 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
2065 FT_Bitmap_New(&AlignedBitmap);
2066 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
2067 {
2068 DPRINT1("Conversion failed\n");
2069 ExFreePoolWithTag(NewEntry, TAG_FONT);
2070 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
2071 return NULL;
2072 }
2073
2074 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
2075 BitmapGlyph->bitmap = AlignedBitmap;
2076
2077 NewEntry->GlyphIndex = GlyphIndex;
2078 NewEntry->Face = Face;
2079 NewEntry->BitmapGlyph = BitmapGlyph;
2080 NewEntry->Height = Height;
2081 NewEntry->mxWorldToDevice = *pmx;
2082
2083 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
2084 if (FontCacheNumEntries++ > MAX_FONT_CACHE)
2085 {
2086 NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
2087 FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph);
2088 RemoveTailList(&FontCacheListHead);
2089 ExFreePoolWithTag(NewEntry, TAG_FONT);
2090 FontCacheNumEntries--;
2091 }
2092
2093 return BitmapGlyph;
2094 }
2095
2096
2097 static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2098 {
2099 pt->x.value = vec->x >> 6;
2100 pt->x.fract = (vec->x & 0x3f) << 10;
2101 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2102 pt->y.value = vec->y >> 6;
2103 pt->y.fract = (vec->y & 0x3f) << 10;
2104 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2105 }
2106
2107 /*
2108 This function builds an FT_Fixed from a float. It puts the integer part
2109 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2110 It fails if the integer part of the float number is greater than SHORT_MAX.
2111 */
2112 static __inline FT_Fixed FT_FixedFromFloat(float f)
2113 {
2114 short value = f;
2115 unsigned short fract = (f - value) * 0xFFFF;
2116 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2117 }
2118
2119 /*
2120 This function builds an FT_Fixed from a FIXED. It simply put f.value
2121 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2122 */
2123 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2124 {
2125 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2126 }
2127
2128 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2129 {
2130 TTPOLYGONHEADER *pph;
2131 TTPOLYCURVE *ppc;
2132 int needed = 0, point = 0, contour, first_pt;
2133 unsigned int pph_start, cpfx;
2134 DWORD type;
2135
2136 for (contour = 0; contour < outline->n_contours; contour++)
2137 {
2138 /* Ignore contours containing one point */
2139 if (point == outline->contours[contour])
2140 {
2141 point++;
2142 continue;
2143 }
2144
2145 pph_start = needed;
2146 pph = (TTPOLYGONHEADER *)(buf + needed);
2147 first_pt = point;
2148 if (buf)
2149 {
2150 pph->dwType = TT_POLYGON_TYPE;
2151 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2152 }
2153 needed += sizeof(*pph);
2154 point++;
2155 while (point <= outline->contours[contour])
2156 {
2157 ppc = (TTPOLYCURVE *)(buf + needed);
2158 type = outline->tags[point] & FT_Curve_Tag_On ?
2159 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2160 cpfx = 0;
2161 do
2162 {
2163 if (buf)
2164 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2165 cpfx++;
2166 point++;
2167 } while (point <= outline->contours[contour] &&
2168 (outline->tags[point] & FT_Curve_Tag_On) ==
2169 (outline->tags[point-1] & FT_Curve_Tag_On));
2170 /* At the end of a contour Windows adds the start point, but
2171 only for Beziers */
2172 if (point > outline->contours[contour] &&
2173 !(outline->tags[point-1] & FT_Curve_Tag_On))
2174 {
2175 if (buf)
2176 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2177 cpfx++;
2178 }
2179 else if (point <= outline->contours[contour] &&
2180 outline->tags[point] & FT_Curve_Tag_On)
2181 {
2182 /* add closing pt for bezier */
2183 if (buf)
2184 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2185 cpfx++;
2186 point++;
2187 }
2188 if (buf)
2189 {
2190 ppc->wType = type;
2191 ppc->cpfx = cpfx;
2192 }
2193 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2194 }
2195 if (buf)
2196 pph->cb = needed - pph_start;
2197 }
2198 return needed;
2199 }
2200
2201 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
2202 {
2203 /* Convert the quadratic Beziers to cubic Beziers.
2204 The parametric eqn for a cubic Bezier is, from PLRM:
2205 r(t) = at^3 + bt^2 + ct + r0
2206 with the control points:
2207 r1 = r0 + c/3
2208 r2 = r1 + (c + b)/3
2209 r3 = r0 + c + b + a
2210
2211 A quadratic Bezier has the form:
2212 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2213
2214 So equating powers of t leads to:
2215 r1 = 2/3 p1 + 1/3 p0
2216 r2 = 2/3 p1 + 1/3 p2
2217 and of course r0 = p0, r3 = p2
2218 */
2219 int contour, point = 0, first_pt;
2220 TTPOLYGONHEADER *pph;
2221 TTPOLYCURVE *ppc;
2222 DWORD pph_start, cpfx, type;
2223 FT_Vector cubic_control[4];
2224 unsigned int needed = 0;
2225
2226 for (contour = 0; contour < outline->n_contours; contour++)
2227 {
2228 pph_start = needed;
2229 pph = (TTPOLYGONHEADER *)(buf + needed);
2230 first_pt = point;
2231 if (buf)
2232 {
2233 pph->dwType = TT_POLYGON_TYPE;
2234 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2235 }
2236 needed += sizeof(*pph);
2237 point++;
2238 while (point <= outline->contours[contour])
2239 {
2240 ppc = (TTPOLYCURVE *)(buf + needed);
2241 type = outline->tags[point] & FT_Curve_Tag_On ?
2242 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2243 cpfx = 0;
2244 do
2245 {
2246 if (type == TT_PRIM_LINE)
2247 {
2248 if (buf)
2249 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2250 cpfx++;
2251 point++;
2252 }
2253 else
2254 {
2255 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2256 so cpfx = 3n */
2257
2258 /* FIXME: Possible optimization in endpoint calculation
2259 if there are two consecutive curves */
2260 cubic_control[0] = outline->points[point-1];
2261 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2262 {
2263 cubic_control[0].x += outline->points[point].x + 1;
2264 cubic_control[0].y += outline->points[point].y + 1;
2265 cubic_control[0].x >>= 1;
2266 cubic_control[0].y >>= 1;
2267 }
2268 if (point+1 > outline->contours[contour])
2269 cubic_control[3] = outline->points[first_pt];
2270 else
2271 {
2272 cubic_control[3] = outline->points[point+1];
2273 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2274 {
2275 cubic_control[3].x += outline->points[point].x + 1;
2276 cubic_control[3].y += outline->points[point].y + 1;
2277 cubic_control[3].x >>= 1;
2278 cubic_control[3].y >>= 1;
2279 }
2280 }
2281 /* r1 = 1/3 p0 + 2/3 p1
2282 r2 = 1/3 p2 + 2/3 p1 */
2283 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2284 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2285 cubic_control[2] = cubic_control[1];
2286 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2287 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2288 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2289 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2290 if (buf)
2291 {
2292 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2293 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2294 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2295 }
2296 cpfx += 3;
2297 point++;
2298 }
2299 } while (point <= outline->contours[contour] &&
2300 (outline->tags[point] & FT_Curve_Tag_On) ==
2301 (outline->tags[point-1] & FT_Curve_Tag_On));
2302 /* At the end of a contour Windows adds the start point,
2303 but only for Beziers and we've already done that.
2304 */
2305 if (point <= outline->contours[contour] &&
2306 outline->tags[point] & FT_Curve_Tag_On)
2307 {
2308 /* This is the closing pt of a bezier, but we've already
2309 added it, so just inc point and carry on */
2310 point++;
2311 }
2312 if (buf)
2313 {
2314 ppc->wType = type;
2315 ppc->cpfx = cpfx;
2316 }
2317 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2318 }
2319 if (buf)
2320 pph->cb = needed - pph_start;
2321 }
2322 return needed;
2323 }
2324
2325 static INT
2326 IntRequestFontSize(PDC dc, FT_Face face, LONG Width, LONG Height)
2327 {
2328 FT_Size_RequestRec req;
2329
2330 if (Width < 0)
2331 Width = -Width;
2332
2333 if (Height < 0)
2334 {
2335 Height = -Height;
2336 }
2337 if (Height == 0)
2338 {
2339 Height = dc->ppdev->devinfo.lfDefaultFont.lfHeight;
2340 }
2341 if (Height == 0)
2342 {
2343 Height = Width;
2344 }
2345
2346 if (Height < 1)
2347 Height = 1;
2348
2349 if (Width > 0xFFFFU)
2350 Width = 0xFFFFU;
2351 if (Height > 0xFFFFU)
2352 Height = 0xFFFFU;
2353
2354 req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
2355 req.width = (FT_Long)(Width << 6);
2356 req.height = (FT_Long)(Height << 6);
2357 req.horiResolution = 0;
2358 req.vertResolution = 0;
2359 return FT_Request_Size(face, &req);
2360 }
2361
2362 BOOL
2363 FASTCALL
2364 TextIntUpdateSize(PDC dc,
2365 PTEXTOBJ TextObj,
2366 PFONTGDI FontGDI,
2367 BOOL bDoLock)
2368 {
2369 FT_Face face;
2370 INT error, n;
2371 FT_CharMap charmap, found;
2372 LOGFONTW *plf;
2373
2374 if (bDoLock)
2375 IntLockFreeType;
2376
2377 face = FontGDI->SharedFace->Face;
2378 if (face->charmap == NULL)
2379 {
2380 DPRINT("WARNING: No charmap selected!\n");
2381 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2382
2383 found = NULL;
2384 for (n = 0; n < face->num_charmaps; n++)
2385 {
2386 charmap = face->charmaps[n];
2387 DPRINT("Found charmap encoding: %i\n", charmap->encoding);
2388 if (charmap->encoding != 0)
2389 {
2390 found = charmap;
2391 break;
2392 }
2393 }
2394 if (!found)
2395 {
2396 DPRINT1("WARNING: Could not find desired charmap!\n");
2397 }
2398 else
2399 {
2400 error = FT_Set_Charmap(face, found);
2401 if (error)
2402 {
2403 DPRINT1("WARNING: Could not set the charmap!\n");
2404 }
2405 }
2406 }
2407
2408 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
2409
2410 error = IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
2411
2412 if (bDoLock)
2413 IntUnLockFreeType;
2414
2415 if (error)
2416 {
2417 DPRINT1("Error in setting pixel sizes: %d\n", error);
2418 return FALSE;
2419 }
2420
2421 return TRUE;
2422 }
2423
2424
2425 /*
2426 * Based on WineEngGetGlyphOutline
2427 *
2428 */
2429 ULONG
2430 FASTCALL
2431 ftGdiGetGlyphOutline(
2432 PDC dc,
2433 WCHAR wch,
2434 UINT iFormat,
2435 LPGLYPHMETRICS pgm,
2436 ULONG cjBuf,
2437 PVOID pvBuf,
2438 LPMAT2 pmat2,
2439 BOOL bIgnoreRotation)
2440 {
2441 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2442 PDC_ATTR pdcattr;
2443 PTEXTOBJ TextObj;
2444 PFONTGDI FontGDI;
2445 HFONT hFont = 0;
2446 GLYPHMETRICS gm;
2447 ULONG Size;
2448 FT_Face ft_face;
2449 FT_UInt glyph_index;
2450 DWORD width, height, pitch, needed = 0;
2451 FT_Bitmap ft_bitmap;
2452 FT_Error error;
2453 INT left, right, top = 0, bottom = 0;
2454 FT_Angle angle = 0;
2455 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2456 FLOAT eM11, widthRatio = 1.0;
2457 FT_Matrix transMat = identityMat;
2458 BOOL needsTransform = FALSE;
2459 INT orientation;
2460 LONG aveWidth;
2461 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
2462 OUTLINETEXTMETRICW *potm;
2463 XFORM xForm;
2464 LOGFONTW *plf;
2465
2466 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
2467 cjBuf, pvBuf, pmat2);
2468
2469 pdcattr = dc->pdcattr;
2470
2471 MatrixS2XForm(&xForm, &dc->pdcattr->mxWorldToDevice);
2472 eM11 = xForm.eM11;
2473
2474 hFont = pdcattr->hlfntNew;
2475 TextObj = RealizeFontInit(hFont);
2476
2477 if (!TextObj)
2478 {
2479 EngSetLastError(ERROR_INVALID_HANDLE);
2480 return GDI_ERROR;
2481 }
2482 FontGDI = ObjToGDI(TextObj->Font, FONT);
2483 ft_face = FontGDI->SharedFace->Face;
2484
2485 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
2486 aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
2487 orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
2488
2489 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2490 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2491 if (!potm)
2492 {
2493 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2494 TEXTOBJ_UnlockText(TextObj);
2495 return GDI_ERROR;
2496 }
2497 IntGetOutlineTextMetrics(FontGDI, Size, potm);
2498
2499 IntLockFreeType;
2500 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
2501 FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
2502
2503 TEXTOBJ_UnlockText(TextObj);
2504
2505 if (iFormat & GGO_GLYPH_INDEX)
2506 {
2507 glyph_index = wch;
2508 iFormat &= ~GGO_GLYPH_INDEX;
2509 }
2510 else glyph_index = FT_Get_Char_Index(ft_face, wch);
2511
2512 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
2513 load_flags |= FT_LOAD_NO_BITMAP;
2514
2515 if (iFormat & GGO_UNHINTED)
2516 {
2517 load_flags |= FT_LOAD_NO_HINTING;
2518 iFormat &= ~GGO_UNHINTED;
2519 }
2520
2521 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
2522 if (error)
2523 {
2524 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
2525 IntUnLockFreeType;
2526 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
2527 return GDI_ERROR;
2528 }
2529 IntUnLockFreeType;
2530
2531 if (aveWidth && potm)
2532 {
2533 widthRatio = (FLOAT)aveWidth * eM11 /
2534 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
2535 }
2536
2537 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2538 right = (INT)((ft_face->glyph->metrics.horiBearingX +
2539 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2540
2541 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2542 lsb = left >> 6;
2543 bbx = (right - left) >> 6;
2544
2545 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
2546
2547 IntLockFreeType;
2548
2549 /* Scaling transform */
2550 /*if (aveWidth)*/
2551 {
2552
2553 FT_Matrix ftmatrix;
2554 FLOATOBJ efTemp;
2555
2556 PMATRIX pmx = DC_pmxWorldToDevice(dc);
2557
2558 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
2559 efTemp = pmx->efM11;
2560 FLOATOBJ_MulLong(&efTemp, 0x00010000);
2561 ftmatrix.xx = FLOATOBJ_GetLong(&efTemp);
2562
2563 efTemp = pmx->efM12;
2564 FLOATOBJ_MulLong(&efTemp, 0x00010000);
2565 ftmatrix.xy = FLOATOBJ_GetLong(&efTemp);
2566
2567 efTemp = pmx->efM21;
2568 FLOATOBJ_MulLong(&efTemp, 0x00010000);
2569 ftmatrix.yx = FLOATOBJ_GetLong(&efTemp);
2570
2571 efTemp = pmx->efM22;
2572 FLOATOBJ_MulLong(&efTemp, 0x00010000);
2573 ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
2574
2575 FT_Matrix_Multiply(&ftmatrix, &transMat);
2576 needsTransform = TRUE;
2577 }
2578
2579 /* Rotation transform */
2580 if (orientation)
2581 {
2582 FT_Matrix rotationMat;
2583 FT_Vector vecAngle;
2584 DPRINT("Rotation Trans!\n");
2585 angle = FT_FixedFromFloat((float)orientation / 10.0);
2586 FT_Vector_Unit(&vecAngle, angle);
2587 rotationMat.xx = vecAngle.x;
2588 rotationMat.xy = -vecAngle.y;
2589 rotationMat.yx = -rotationMat.xy;
2590 rotationMat.yy = rotationMat.xx;
2591 FT_Matrix_Multiply(&rotationMat, &transMat);
2592 needsTransform = TRUE;
2593 }
2594
2595 /* Extra transformation specified by caller */
2596 if (pmat2)
2597 {
2598 FT_Matrix extraMat;
2599 DPRINT("MAT2 Matrix Trans!\n");
2600 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
2601 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
2602 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
2603 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
2604 FT_Matrix_Multiply(&extraMat, &transMat);
2605 needsTransform = TRUE;
2606 }
2607
2608 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
2609
2610 if (!needsTransform)
2611 {
2612 DPRINT("No Need to be Transformed!\n");
2613 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2614 bottom = (ft_face->glyph->metrics.horiBearingY -
2615 ft_face->glyph->metrics.height) & -64;
2616 gm.gmCellIncX = adv;
2617 gm.gmCellIncY = 0;
2618 }
2619 else
2620 {
2621 INT xc, yc;
2622 FT_Vector vec;
2623 for (xc = 0; xc < 2; xc++)
2624 {
2625 for (yc = 0; yc < 2; yc++)
2626 {
2627 vec.x = (ft_face->glyph->metrics.horiBearingX +
2628 xc * ft_face->glyph->metrics.width);
2629 vec.y = ft_face->glyph->metrics.horiBearingY -
2630 yc * ft_face->glyph->metrics.height;
2631 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
2632 FT_Vector_Transform(&vec, &transMat);
2633 if (xc == 0 && yc == 0)
2634 {
2635 left = right = vec.x;
2636 top = bottom = vec.y;
2637 }
2638 else
2639 {
2640 if (vec.x < left) left = vec.x;
2641 else if (vec.x > right) right = vec.x;
2642 if (vec.y < bottom) bottom = vec.y;
2643 else if (vec.y > top) top = vec.y;
2644 }
2645 }
2646 }
2647 left = left & -64;
2648 right = (right + 63) & -64;
2649 bottom = bottom & -64;
2650 top = (top + 63) & -64;
2651
2652 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2653 vec.x = ft_face->glyph->metrics.horiAdvance;
2654 vec.y = 0;
2655 FT_Vector_Transform(&vec, &transMat);
2656 gm.gmCellIncX = (vec.x+63) >> 6;
2657 gm.gmCellIncY = -((vec.y+63) >> 6);
2658 }
2659 gm.gmBlackBoxX = (right - left) >> 6;
2660 gm.gmBlackBoxY = (top - bottom) >> 6;
2661 gm.gmptGlyphOrigin.x = left >> 6;
2662 gm.gmptGlyphOrigin.y = top >> 6;
2663
2664 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
2665 gm.gmCellIncX, gm.gmCellIncY,
2666 gm.gmBlackBoxX, gm.gmBlackBoxY,
2667 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
2668
2669 IntUnLockFreeType;
2670
2671
2672 if (iFormat == GGO_METRICS)
2673 {
2674 DPRINT("GGO_METRICS Exit!\n");
2675 *pgm = gm;
2676 return 1; /* FIXME */
2677 }
2678
2679 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
2680 {
2681 DPRINT1("Loaded a bitmap\n");
2682 return GDI_ERROR;
2683 }
2684
2685 switch (iFormat)
2686 {
2687 case GGO_BITMAP:
2688 width = gm.gmBlackBoxX;
2689 height = gm.gmBlackBoxY;
2690 pitch = ((width + 31) >> 5) << 2;
2691 needed = pitch * height;
2692
2693 if (!pvBuf || !cjBuf) break;
2694 if (!needed) return GDI_ERROR; /* empty glyph */
2695 if (needed > cjBuf)
2696 return GDI_ERROR;
2697
2698 switch (ft_face->glyph->format)
2699 {
2700 case ft_glyph_format_bitmap:
2701 {
2702 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
2703 INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
2704 INT h = min( height, ft_face->glyph->bitmap.rows );
2705 while (h--)
2706 {
2707 RtlCopyMemory(dst, src, w);
2708 src += ft_face->glyph->bitmap.pitch;
2709 dst += pitch;
2710 }
2711 break;
2712 }
2713
2714 case ft_glyph_format_outline:
2715 ft_bitmap.width = width;
2716 ft_bitmap.rows = height;
2717 ft_bitmap.pitch = pitch;
2718 ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
2719 ft_bitmap.buffer = pvBuf;
2720
2721 IntLockFreeType;
2722 if (needsTransform)
2723 {
2724 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2725 }
2726 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2727 /* Note: FreeType will only set 'black' bits for us. */
2728 RtlZeroMemory(pvBuf, needed);
2729 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2730 IntUnLockFreeType;
2731 break;
2732
2733 default:
2734 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
2735 return GDI_ERROR;
2736 }
2737 break;
2738
2739 case GGO_GRAY2_BITMAP:
2740 case GGO_GRAY4_BITMAP:
2741 case GGO_GRAY8_BITMAP:
2742 {
2743 unsigned int mult, row, col;
2744 BYTE *start, *ptr;
2745
2746 width = gm.gmBlackBoxX;
2747 height = gm.gmBlackBoxY;
2748 pitch = (width + 3) / 4 * 4;
2749 needed = pitch * height;
2750
2751 if (!pvBuf || !cjBuf) break;
2752 if (!needed) return GDI_ERROR; /* empty glyph */
2753 if (needed > cjBuf)
2754 return GDI_ERROR;
2755
2756 switch (ft_face->glyph->format)
2757 {
2758 case ft_glyph_format_bitmap:
2759 {
2760 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
2761 INT h = min( height, ft_face->glyph->bitmap.rows );
2762 INT x;
2763 while (h--)
2764 {
2765 for (x = 0; (UINT)x < pitch; x++)
2766 {
2767 if (x < ft_face->glyph->bitmap.width)
2768 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
2769 else
2770 dst[x] = 0;
2771 }
2772 src += ft_face->glyph->bitmap.pitch;
2773 dst += pitch;
2774 }
2775 break;
2776 }
2777 case ft_glyph_format_outline:
2778 {
2779 ft_bitmap.width = width;
2780 ft_bitmap.rows = height;
2781 ft_bitmap.pitch = pitch;
2782 ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
2783 ft_bitmap.buffer = pvBuf;
2784
2785 IntLockFreeType;
2786 if (needsTransform)
2787 {
2788 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2789 }
2790 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2791 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
2792 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2793 IntUnLockFreeType;
2794
2795 if (iFormat == GGO_GRAY2_BITMAP)
2796 mult = 4;
2797 else if (iFormat == GGO_GRAY4_BITMAP)
2798 mult = 16;
2799 else if (iFormat == GGO_GRAY8_BITMAP)
2800 mult = 64;
2801 else
2802 {
2803 return GDI_ERROR;
2804 }
2805
2806 start = pvBuf;
2807 for (row = 0; row < height; row++)
2808 {
2809 ptr = start;
2810 for (col = 0; col < width; col++, ptr++)
2811 {
2812 *ptr = (((int)*ptr) * mult + 128) / 256;
2813 }
2814 start += pitch;
2815 }
2816
2817 break;
2818 }
2819 default:
2820 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
2821 return GDI_ERROR;
2822 }
2823 }
2824
2825 case GGO_NATIVE:
2826 {
2827 FT_Outline *outline = &ft_face->glyph->outline;
2828
2829 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
2830
2831 IntLockFreeType;
2832 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
2833
2834 needed = get_native_glyph_outline(outline, cjBuf, NULL);
2835
2836 if (!pvBuf || !cjBuf)
2837 {
2838 IntUnLockFreeType;
2839 break;
2840 }
2841 if (needed > cjBuf)
2842 {
2843 IntUnLockFreeType;
2844 return GDI_ERROR;
2845 }
2846 get_native_glyph_outline(outline, cjBuf, pvBuf);
2847 IntUnLockFreeType;
2848 break;
2849 }
2850 case GGO_BEZIER:
2851 {
2852 FT_Outline *outline = &ft_face->glyph->outline;
2853 if (cjBuf == 0) pvBuf = NULL;
2854
2855 if (needsTransform && pvBuf)
2856 {
2857 IntLockFreeType;
2858 FT_Outline_Transform(outline, &transMat);
2859 IntUnLockFreeType;
2860 }
2861 needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
2862
2863 if (!pvBuf || !cjBuf)
2864 break;
2865 if (needed > cjBuf)
2866 return GDI_ERROR;
2867
2868 get_bezier_glyph_outline(outline, cjBuf, pvBuf);
2869 break;
2870 }
2871
2872 default:
2873 DPRINT1("Unsupported format %u\n", iFormat);
2874 return GDI_ERROR;
2875 }
2876
2877 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
2878 *pgm = gm;
2879 return needed;
2880 }
2881
2882 BOOL
2883 FASTCALL
2884 TextIntGetTextExtentPoint(PDC dc,
2885 PTEXTOBJ TextObj,
2886 LPCWSTR String,
2887 INT Count,
2888 ULONG MaxExtent,
2889 LPINT Fit,
2890 LPINT Dx,
2891 LPSIZE Size,
2892 FLONG fl)
2893 {
2894 PFONTGDI FontGDI;
2895 FT_Face face;
2896 FT_GlyphSlot glyph;
2897 FT_BitmapGlyph realglyph;
2898 INT error, glyph_index, i, previous;
2899 ULONGLONG TotalWidth = 0;
2900 BOOL use_kerning;
2901 FT_Render_Mode RenderMode;
2902 BOOLEAN Render;
2903 PMATRIX pmxWorldToDevice;
2904 LOGFONTW *plf;
2905 BOOL EmuBold, EmuItalic;
2906
2907 FontGDI = ObjToGDI(TextObj->Font, FONT);
2908
2909 face = FontGDI->SharedFace->Face;
2910 if (NULL != Fit)
2911 {
2912 *Fit = 0;
2913 }
2914
2915 IntLockFreeType;
2916
2917 TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
2918
2919 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
2920 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
2921 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
2922
2923 Render = IntIsFontRenderingEnabled();
2924 if (Render)
2925 RenderMode = IntGetFontRenderMode(plf);
2926 else
2927 RenderMode = FT_RENDER_MODE_MONO;
2928
2929
2930 /* Get the DC's world-to-device transformation matrix */
2931 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
2932 FtSetCoordinateTransform(face, pmxWorldToDevice);
2933
2934 use_kerning = FT_HAS_KERNING(face);
2935 previous = 0;
2936
2937 for (i = 0; i < Count; i++)
2938 {
2939 if (fl & GTEF_INDICES)
2940 glyph_index = *String;
2941 else
2942 glyph_index = FT_Get_Char_Index(face, *String);
2943
2944 if (EmuBold || EmuItalic)
2945 realglyph = NULL;
2946 else
2947 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
2948 plf->lfHeight, pmxWorldToDevice);
2949
2950 if (EmuBold || EmuItalic || !realglyph)
2951 {
2952 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2953 if (error)
2954 {
2955 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
2956 break;
2957 }
2958
2959 glyph = face->glyph;
2960 if (EmuBold || EmuItalic)
2961 {
2962 if (EmuBold)
2963 FT_GlyphSlot_Embolden(glyph);
2964 if (EmuItalic)
2965 FT_GlyphSlot_Oblique(glyph);
2966 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
2967 }
2968 else
2969 {
2970 realglyph = ftGdiGlyphCacheSet(face,
2971 glyph_index,
2972 plf->lfHeight,
2973 pmxWorldToDevice,
2974 glyph,
2975 RenderMode);
2976 }
2977
2978 if (!realglyph)
2979 {
2980 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
2981 break;
2982 }
2983 }
2984
2985 /* Retrieve kerning distance */
2986 if (use_kerning && previous && glyph_index)
2987 {
2988 FT_Vector delta;
2989 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
2990 TotalWidth += delta.x;
2991 }
2992
2993 TotalWidth += realglyph->root.advance.x >> 10;
2994
2995 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
2996 {
2997 *Fit = i + 1;
2998 }
2999 if (NULL != Dx)
3000 {
3001 Dx[i] = (TotalWidth + 32) >> 6;
3002 }
3003
3004 if (EmuBold || EmuItalic)
3005 {
3006 FT_Done_Glyph((FT_Glyph)realglyph);
3007 realglyph = NULL;
3008 }
3009
3010 previous = glyph_index;
3011 String++;
3012 }
3013 IntUnLockFreeType;
3014
3015 Size->cx = (TotalWidth + 32) >> 6;
3016 Size->cy = (plf->lfHeight == 0 ?
3017 dc->ppdev->devinfo.lfDefaultFont.lfHeight :
3018 abs(plf->lfHeight));
3019 Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
3020
3021 return TRUE;
3022 }
3023
3024
3025 INT
3026 FASTCALL
3027 ftGdiGetTextCharsetInfo(
3028 PDC Dc,
3029 LPFONTSIGNATURE lpSig,
3030 DWORD dwFlags)
3031 {
3032 PDC_ATTR pdcattr;
3033 UINT Ret = DEFAULT_CHARSET;
3034 INT i;
3035 HFONT hFont;
3036 PTEXTOBJ TextObj;
3037 PFONTGDI FontGdi;
3038 FONTSIGNATURE fs;
3039 TT_OS2 *pOS2;
3040 FT_Face Face;
3041 CHARSETINFO csi;
3042 DWORD cp, fs0;
3043 USHORT usACP, usOEM;
3044
3045 pdcattr = Dc->pdcattr;
3046 hFont = pdcattr->hlfntNew;
3047 TextObj = RealizeFontInit(hFont);
3048
3049 if (!TextObj)
3050 {
3051 EngSetLastError(ERROR_INVALID_HANDLE);
3052 return Ret;
3053 }
3054 FontGdi = ObjToGDI(TextObj->Font, FONT);
3055 Face = FontGdi->SharedFace->Face;
3056 TEXTOBJ_UnlockText(TextObj);
3057
3058 IntLockFreeType;
3059 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3060 IntUnLockFreeType;
3061 memset(&fs, 0, sizeof(FONTSIGNATURE));
3062 if (NULL != pOS2)
3063 {
3064 fs.fsCsb[0] = pOS2->ulCodePageRange1;
3065 fs.fsCsb[1] = pOS2->ulCodePageRange2;
3066 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3067 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3068 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3069 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3070 if (pOS2->version == 0)
3071 {
3072 FT_UInt dummy;
3073
3074 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
3075 fs.fsCsb[0] |= FS_LATIN1;
3076 else
3077 fs.fsCsb[0] |= FS_SYMBOL;
3078 }
3079 }
3080 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
3081 if (fs.fsCsb[0] == 0)
3082 { /* Let's see if we can find any interesting cmaps */
3083 for (i = 0; i < Face->num_charmaps; i++)
3084 {
3085 switch (Face->charmaps[i]->encoding)
3086 {
3087 case FT_ENCODING_UNICODE:
3088 case FT_ENCODING_APPLE_ROMAN:
3089 fs.fsCsb[0] |= FS_LATIN1;
3090 break;
3091 case FT_ENCODING_MS_SYMBOL:
3092 fs.fsCsb[0] |= FS_SYMBOL;
3093 break;
3094 default:
3095 break;
3096 }
3097 }
3098 }
3099 if (lpSig)
3100 {
3101 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
3102 }
3103
3104 RtlGetDefaultCodePage(&usACP, &usOEM);
3105 cp = usACP;
3106
3107 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
3108 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
3109 {
3110 DPRINT("Hit 1\n");
3111 Ret = csi.ciCharset;
3112 goto Exit;
3113 }
3114
3115 for (i = 0; i < MAXTCIINDEX; i++)
3116 {
3117 fs0 = 1L << i;
3118 if (fs.fsCsb[0] & fs0)
3119 {
3120 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
3121