366e657f5df2ad5a1d3a1f63c6ddb9cf67f37977
[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 {
3122 // *cp = csi.ciACP;
3123 DPRINT("Hit 2\n");
3124 Ret = csi.ciCharset;
3125 goto Exit;
3126 }
3127 else
3128 DPRINT1("TCI failing on %x\n", fs0);
3129 }
3130 }
3131 Exit:
3132 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
3133 return (MAKELONG(csi.ciACP, csi.ciCharset));
3134 }
3135
3136
3137 DWORD
3138 FASTCALL
3139 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
3140 {
3141 DWORD size = 0;
3142 DWORD num_ranges = 0;
3143 FT_Face face = Font->SharedFace->Face;
3144
3145 if (face->charmap->encoding == FT_ENCODING_UNICODE)
3146 {
3147 FT_UInt glyph_code = 0;
3148 FT_ULong char_code, char_code_prev;
3149
3150 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
3151
3152 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
3153 face->num_glyphs, glyph_code, char_code);
3154
3155 if (!glyph_code) return 0;
3156
3157 if (glyphset)
3158 {
3159 glyphset->ranges[0].wcLow = (USHORT)char_code;
3160 glyphset->ranges[0].cGlyphs = 0;
3161 glyphset->cGlyphsSupported = 0;
3162 }
3163
3164 num_ranges = 1;
3165 while (glyph_code)
3166 {
3167 if (char_code < char_code_prev)
3168 {
3169 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
3170 return 0;
3171 }
3172 if (char_code - char_code_prev > 1)
3173 {
3174 num_ranges++;
3175 if (glyphset)
3176 {
3177 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
3178 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
3179 glyphset->cGlyphsSupported++;
3180 }
3181 }
3182 else if (glyphset)
3183 {
3184 glyphset->ranges[num_ranges - 1].cGlyphs++;
3185 glyphset->cGlyphsSupported++;
3186 }
3187 char_code_prev = char_code;
3188 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
3189 }
3190 }
3191 else
3192 DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
3193
3194 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
3195 if (glyphset)
3196 {
3197 glyphset->cbThis = size;
3198 glyphset->cRanges = num_ranges;
3199 glyphset->flAccel = 0;
3200 }
3201 return size;
3202 }
3203
3204
3205 BOOL
3206 FASTCALL
3207 ftGdiGetTextMetricsW(
3208 HDC hDC,
3209 PTMW_INTERNAL ptmwi)
3210 {
3211 PDC dc;
3212 PDC_ATTR pdcattr;
3213 PTEXTOBJ TextObj;
3214 PFONTGDI FontGDI;
3215 FT_Face Face;
3216 TT_OS2 *pOS2;
3217 TT_HoriHeader *pHori;
3218 FT_WinFNT_HeaderRec Win;
3219 ULONG Error;
3220 NTSTATUS Status = STATUS_SUCCESS;
3221 LOGFONTW *plf;
3222
3223 if (!ptmwi)
3224 {
3225 EngSetLastError(STATUS_INVALID_PARAMETER);
3226 return FALSE;
3227 }
3228
3229 if (!(dc = DC_LockDc(hDC)))
3230 {
3231 EngSetLastError(ERROR_INVALID_HANDLE);
3232 return FALSE;
3233 }
3234 pdcattr = dc->pdcattr;
3235 TextObj = RealizeFontInit(pdcattr->hlfntNew);
3236 if (NULL != TextObj)
3237 {
3238 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3239 FontGDI = ObjToGDI(TextObj->Font, FONT);
3240
3241 Face = FontGDI->SharedFace->Face;
3242 IntLockFreeType;
3243 Error = IntRequestFontSize(dc, Face, plf->lfWidth, plf->lfHeight);
3244 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
3245 IntUnLockFreeType;
3246 if (0 != Error)
3247 {
3248 DPRINT1("Error in setting pixel sizes: %u\n", Error);
3249 Status = STATUS_UNSUCCESSFUL;
3250 }
3251 else
3252 {
3253 FT_Face Face = FontGDI->SharedFace->Face;
3254 Status = STATUS_SUCCESS;
3255
3256 IntLockFreeType;
3257 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3258 if (NULL == pOS2)
3259 {
3260 DPRINT1("Can't find OS/2 table - not TT font?\n");
3261 Status = STATUS_INTERNAL_ERROR;
3262 }
3263
3264 pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
3265 if (NULL == pHori)
3266 {
3267 DPRINT1("Can't find HHEA table - not TT font?\n");
3268 Status = STATUS_INTERNAL_ERROR;
3269 }
3270
3271 Error = FT_Get_WinFNT_Header(Face, &Win);
3272
3273 IntUnLockFreeType;
3274
3275 if (NT_SUCCESS(Status))
3276 {
3277 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
3278
3279 /* FIXME: Fill Diff member */
3280 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
3281 }
3282 }
3283 TEXTOBJ_UnlockText(TextObj);
3284 }
3285 else
3286 {
3287 Status = STATUS_INVALID_HANDLE;
3288 }
3289 DC_UnlockDc(dc);
3290
3291 if (!NT_SUCCESS(Status))
3292 {
3293 SetLastNtError(Status);
3294 return FALSE;
3295 }
3296 return TRUE;
3297 }
3298
3299
3300 DWORD
3301 FASTCALL
3302 ftGdiGetFontData(
3303 PFONTGDI FontGdi,
3304 DWORD Table,
3305 DWORD Offset,
3306 PVOID Buffer,
3307 DWORD Size)
3308 {
3309 DWORD Result = GDI_ERROR;
3310 FT_Face Face = FontGdi->SharedFace->Face;
3311
3312 IntLockFreeType;
3313
3314 if (FT_IS_SFNT(Face))
3315 {
3316 if (Table)
3317 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
3318 (Table << 8 & 0xFF0000);
3319
3320 if (!Buffer) Size = 0;
3321
3322 if (Buffer && Size)
3323 {
3324 FT_Error Error;
3325 FT_ULong Needed = 0;
3326
3327 Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
3328
3329 if ( !Error && Needed < Size) Size = Needed;
3330 }
3331 if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
3332 Result = Size;
3333 }
3334
3335 IntUnLockFreeType;
3336
3337 return Result;
3338 }
3339
3340 static __inline BOOLEAN
3341 SubstituteFontNameByKey(PUNICODE_STRING FaceName,
3342 LPCWSTR Key)
3343 {
3344 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
3345 NTSTATUS Status;
3346 UNICODE_STRING Value;
3347
3348 RtlInitUnicodeString(&Value, NULL);
3349
3350 QueryTable[0].QueryRoutine = NULL;
3351 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
3352 RTL_QUERY_REGISTRY_REQUIRED;
3353 QueryTable[0].Name = FaceName->Buffer;
3354 QueryTable[0].EntryContext = &Value;
3355 QueryTable[0].DefaultType = REG_NONE;
3356 QueryTable[0].DefaultData = NULL;
3357 QueryTable[0].DefaultLength = 0;
3358
3359 QueryTable[1].QueryRoutine = NULL;
3360 QueryTable[1].Name = NULL;
3361
3362 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
3363 Key,
3364 QueryTable,
3365 NULL,
3366 NULL);
3367 if (NT_SUCCESS(Status))
3368 {
3369 RtlFreeUnicodeString(FaceName);
3370 *FaceName = Value;
3371
3372 /* truncate */
3373 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < FaceName->Length)
3374 {
3375 FaceName->Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
3376 FaceName->Buffer[LF_FACESIZE - 1] = UNICODE_NULL;
3377 }
3378 }
3379
3380 return NT_SUCCESS(Status);
3381 }
3382
3383 static __inline BOOL
3384 SubstituteFontName(PUNICODE_STRING FaceName)
3385 {
3386 UINT Level;
3387 const UINT MaxLevel = 10;
3388
3389 if (FaceName->Buffer[0] == 0)
3390 return FALSE;
3391
3392 for (Level = 0; Level < MaxLevel; ++Level)
3393 {
3394 /* NOTE: SubstituteFontNameByKey changes FaceName. Be careful... */
3395 if (!SubstituteFontNameByKey(FaceName, L"FontSubstitutes"))
3396 break;
3397 }
3398 return (Level > 0);
3399 }
3400
3401 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
3402 static UINT FASTCALL
3403 GetFontPenalty(LOGFONTW * LogFont,
3404 PUNICODE_STRING RequestedNameW,
3405 PUNICODE_STRING ActualNameW,
3406 PUNICODE_STRING FullFaceNameW,
3407 PFONTGDI FontGDI,
3408 OUTLINETEXTMETRICW * Otm,
3409 TEXTMETRICW * TM,
3410 const char * style_name)
3411 {
3412 ULONG Penalty = 0;
3413 BYTE Byte;
3414 LONG Long;
3415 BOOL fFixedSys = FALSE, fNeedScaling = FALSE;
3416 const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
3417
3418 /* FIXME: Aspect Penalty 30 */
3419 /* FIXME: IntSizeSynth Penalty 20 */
3420 /* FIXME: SmallPenalty Penalty 1 */
3421 /* FIXME: FaceNameSubst Penalty 500 */
3422
3423 if (RtlEqualUnicodeString(RequestedNameW, &SystemW, TRUE))
3424 {
3425 /* "System" font */
3426 if (TM->tmCharSet != UserCharSet)
3427 {
3428 /* CharSet Penalty 65000 */
3429 /* Requested charset does not match the candidate's. */
3430 Penalty += 65000;
3431 }
3432 }
3433 else if (RtlEqualUnicodeString(RequestedNameW, &FixedSysW, TRUE))
3434 {
3435 /* "FixedSys" font */
3436 if (TM->tmCharSet != UserCharSet)
3437 {
3438 /* CharSet Penalty 65000 */
3439 /* Requested charset does not match the candidate's. */
3440 Penalty += 65000;
3441 }
3442 fFixedSys = TRUE;
3443 }
3444 else /* Request is non-"System" font */
3445 {
3446 Byte = LogFont->lfCharSet;
3447 if (Byte == DEFAULT_CHARSET)
3448 {
3449 if (RtlEqualUnicodeString(RequestedNameW, &MarlettW, TRUE))
3450 {
3451 if (Byte == ANSI_CHARSET)
3452 {
3453 DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
3454 }
3455 /* We assume SYMBOL_CHARSET for "Marlett" font */
3456 Byte = SYMBOL_CHARSET;
3457 }
3458 }
3459
3460 if (Byte != TM->tmCharSet)
3461 {
3462 if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
3463 {
3464 /* CharSet Penalty 65000 */
3465 /* Requested charset does not match the candidate's. */
3466 Penalty += 65000;
3467 }
3468 else
3469 {
3470 if (UserCharSet != TM->tmCharSet)
3471 {
3472 /* UNDOCUMENTED */
3473 Penalty += 10;
3474 }
3475 if (ANSI_CHARSET != TM->tmCharSet)
3476 {
3477 /* UNDOCUMENTED */
3478 Penalty += 10;
3479 }
3480 }
3481 }
3482 }
3483
3484 Byte = LogFont->lfOutPrecision;
3485 if (Byte == OUT_DEFAULT_PRECIS)
3486 Byte = OUT_OUTLINE_PRECIS; /* Is it OK? */
3487 switch (Byte)
3488 {
3489 case OUT_DEVICE_PRECIS:
3490 if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
3491 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
3492 {
3493 /* OutputPrecision Penalty 19000 */
3494 /* Requested OUT_STROKE_PRECIS, but the device can't do it
3495 or the candidate is not a vector font. */
3496 Penalty += 19000;
3497 }
3498 break;
3499 default:
3500 if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
3501 {
3502 /* OutputPrecision Penalty 19000 */
3503 /* Or OUT_STROKE_PRECIS not requested, and the candidate
3504 is a vector font that requires GDI support. */
3505 Penalty += 19000;
3506 }
3507 break;
3508 }
3509
3510 Byte = (LogFont->lfPitchAndFamily & 0x0F);
3511 if (Byte == DEFAULT_PITCH)
3512 Byte = VARIABLE_PITCH;
3513 if (fFixedSys)
3514 {
3515 /* "FixedSys" font should be fixed-pitch */
3516 Byte = FIXED_PITCH;
3517 }
3518 if (Byte == FIXED_PITCH)
3519 {
3520 if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
3521 {
3522 /* FixedPitch Penalty 15000 */
3523 /* Requested a fixed pitch font, but the candidate is a
3524 variable pitch font. */
3525 Penalty += 15000;
3526 }
3527 }
3528 if (Byte == VARIABLE_PITCH)
3529 {
3530 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
3531 {
3532 /* PitchVariable Penalty 350 */
3533 /* Requested a variable pitch font, but the candidate is not a
3534 variable pitch font. */
3535 Penalty += 350;
3536 }
3537 }
3538
3539 Byte = (LogFont->lfPitchAndFamily & 0x0F);
3540 if (Byte == DEFAULT_PITCH)
3541 {
3542 if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
3543 {
3544 /* DefaultPitchFixed Penalty 1 */
3545 /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
3546 Penalty += 1;
3547 }
3548 }
3549
3550 if (RequestedNameW->Buffer[0])
3551 {
3552 if (RtlEqualUnicodeString(RequestedNameW, FullFaceNameW, TRUE))
3553 {
3554 /* matched with full face name */
3555 }
3556 else if (RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE))
3557 {
3558 /* matched with actual name */
3559 }
3560 else
3561 {
3562 /* try the localized name */
3563 UNICODE_STRING LocalNameW;
3564 FT_Face Face = FontGDI->SharedFace->Face;
3565 IntGetFontLocalizedName(&LocalNameW, Face);
3566 if (RtlEqualUnicodeString(RequestedNameW, &LocalNameW, TRUE))
3567 {
3568 /* matched with localizied name */
3569 }
3570 else
3571 {
3572 /* FaceName Penalty 10000 */
3573 /* Requested a face name, but the candidate's face name
3574 does not match. */
3575 Penalty += 10000;
3576 }
3577 RtlFreeUnicodeString(&LocalNameW);
3578 }
3579 }
3580
3581 Byte = (LogFont->lfPitchAndFamily & 0xF0);
3582 if (Byte != FF_DONTCARE)
3583 {
3584 if (Byte != (TM->tmPitchAndFamily & 0xF0))
3585 {
3586 /* Family Penalty 9000 */
3587 /* Requested a family, but the candidate's family is different. */
3588 Penalty += 9000;
3589 }
3590 if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
3591 {
3592 /* FamilyUnknown Penalty 8000 */
3593 /* Requested a family, but the candidate has no family. */
3594 Penalty += 8000;
3595 }
3596 }
3597
3598 /* Is the candidate a non-vector font? */
3599 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
3600 {
3601 /* Is lfHeight specified? */
3602 if (LogFont->lfHeight != 0)
3603 {
3604 if (labs(LogFont->lfHeight) < TM->tmHeight)
3605 {
3606 /* HeightBigger Penalty 600 */
3607 /* The candidate is a nonvector font and is bigger than the
3608 requested height. */
3609 Penalty += 600;
3610 /* HeightBiggerDifference Penalty 150 */
3611 /* The candidate is a raster font and is larger than the
3612 requested height. Penalty * height difference */
3613 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
3614
3615 fNeedScaling = TRUE;
3616 }
3617 if (TM->tmHeight < labs(LogFont->lfHeight))
3618 {
3619 /* HeightSmaller Penalty 150 */
3620 /* The candidate is a raster font and is smaller than the
3621 requested height. Penalty * height difference */
3622 Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
3623
3624 fNeedScaling = TRUE;
3625 }
3626 }
3627 }
3628
3629 switch (LogFont->lfPitchAndFamily & 0xF0)
3630 {
3631 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
3632 switch (TM->tmPitchAndFamily & 0xF0)
3633 {
3634 case FF_DECORATIVE: case FF_SCRIPT:
3635 /* FamilyUnlikely Penalty 50 */
3636 /* Requested a roman/modern/swiss family, but the
3637 candidate is decorative/script. */
3638 Penalty += 50;
3639 break;
3640 default:
3641 break;
3642 }
3643 break;
3644 case FF_DECORATIVE: case FF_SCRIPT:
3645 switch (TM->tmPitchAndFamily & 0xF0)
3646 {
3647 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
3648 /* FamilyUnlikely Penalty 50 */
3649 /* Or requested decorative/script, and the candidate is
3650 roman/modern/swiss. */
3651 Penalty += 50;
3652 break;
3653 default:
3654 break;
3655 }
3656 default:
3657 break;
3658 }
3659
3660 if (LogFont->lfWidth != 0)
3661 {
3662 if (LogFont->lfWidth != TM->tmAveCharWidth)
3663 {
3664 /* Width Penalty 50 */
3665 /* Requested a nonzero width, but the candidate's width
3666 doesn't match. Penalty * width difference */
3667 Penalty += 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth);
3668
3669 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
3670 fNeedScaling = TRUE;
3671 }
3672 }
3673
3674 if (fNeedScaling)
3675 {
3676 /* SizeSynth Penalty 50 */
3677 /* The candidate is a raster font that needs scaling by GDI. */
3678 Penalty += 50;
3679 }
3680
3681 if (!!LogFont->lfItalic != !!TM->tmItalic)
3682 {
3683 if (!LogFont->lfItalic && ItalicFromStyle(style_name))
3684 {
3685 /* Italic Penalty 4 */
3686 /* Requested font and candidate font do not agree on italic status,
3687 and the desired result cannot be simulated. */
3688 /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
3689 Penalty += 40;
3690 }
3691 else if (LogFont->lfItalic && !ItalicFromStyle(style_name))
3692 {
3693 /* ItalicSim Penalty 1 */
3694 /* Requested italic font but the candidate is not italic,
3695 although italics can be simulated. */
3696 Penalty += 1;
3697 }
3698 }
3699
3700 if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
3701 {
3702 if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
3703 {
3704 /* NotTrueType Penalty 4 */
3705 /* Requested OUT_TT_PRECIS, but the candidate is not a
3706 TrueType font. */
3707 Penalty += 4;
3708 }
3709 }
3710
3711 Long = LogFont->lfWeight;
3712 if (LogFont->lfWeight == FW_DONTCARE)
3713 Long = FW_NORMAL;
3714 if (Long != TM->tmWeight)
3715 {
3716 /* Weight Penalty 3 */
3717 /* The candidate's weight does not match the requested weight.
3718 Penalty * (weight difference/10) */
3719 Penalty += 3 * (labs(Long - TM->tmWeight) / 10);
3720 }
3721
3722 if (!LogFont->lfUnderline && TM->tmUnderlined)
3723 {
3724 /* Underline Penalty 3 */
3725 /* Requested font has no underline, but the candidate is
3726 underlined. */
3727 Penalty += 3;
3728 }
3729
3730 if (!LogFont->lfStrikeOut && TM->tmStruckOut)
3731 {
3732 /* StrikeOut Penalty 3 */
3733 /* Requested font has no strike-out, but the candidate is
3734 struck out. */
3735 Penalty += 3;
3736 }
3737
3738 /* Is the candidate a non-vector font? */
3739 if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
3740 {
3741 if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
3742 {
3743 /* VectorHeightSmaller Penalty 2 */
3744 /* Candidate is a vector font that is smaller than the
3745 requested height. Penalty * height difference */
3746 Penalty += 2 * labs(TM->tmHeight - LogFont->lfHeight);
3747 }
3748 if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
3749 {
3750 /* VectorHeightBigger Penalty 1 */
3751 /* Candidate is a vector font that is bigger than the
3752 requested height. Penalty * height difference */
3753 Penalty += 1 * labs(TM->tmHeight - LogFont->lfHeight);
3754 }
3755 }
3756
3757 if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
3758 {
3759 /* DeviceFavor Penalty 2 */
3760 /* Extra penalty for all nondevice fonts. */
3761 Penalty += 2;
3762 }
3763
3764 if (Penalty < 200)
3765 {
3766 DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
3767 "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
3768 "tmCharSet:%d, tmWeight:%ld\n",
3769 Penalty, RequestedNameW->Buffer, ActualNameW->Buffer,
3770 LogFont->lfCharSet, LogFont->lfWeight,
3771 TM->tmCharSet, TM->tmWeight);
3772 }
3773
3774 return Penalty; /* success */
3775 }
3776
3777 static __inline VOID
3778 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, LOGFONTW *LogFont,
3779 PUNICODE_STRING pRequestedNameW,
3780 PUNICODE_STRING pActualNameW, PLIST_ENTRY Head)
3781 {
3782 ULONG Penalty;
3783 NTSTATUS Status;
3784 PLIST_ENTRY Entry;
3785 PFONT_ENTRY CurrentEntry;
3786 FONTGDI *FontGDI;
3787 ANSI_STRING ActualNameA;
3788 UNICODE_STRING ActualNameW, FullFaceNameW;
3789 OUTLINETEXTMETRICW *Otm = NULL;
3790 UINT OtmSize, OldOtmSize = 0;
3791 TEXTMETRICW *TM;
3792 FT_Face Face;
3793 LPBYTE pb;
3794
3795 ASSERT(FontObj);
3796 ASSERT(MatchPenalty);
3797 ASSERT(LogFont);
3798 ASSERT(pRequestedNameW);
3799 ASSERT(Head);
3800
3801 /* get the FontObj of lowest penalty */
3802 Entry = Head->Flink;
3803 while (Entry != Head)
3804 {
3805 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
3806 FontGDI = CurrentEntry->Font;
3807 ASSERT(FontGDI);
3808 Face = FontGDI->SharedFace->Face;
3809
3810 /* create actual name */
3811 RtlInitAnsiString(&ActualNameA, Face->family_name);
3812 Status = RtlAnsiStringToUnicodeString(&ActualNameW, &ActualNameA, TRUE);
3813 if (!NT_SUCCESS(Status))
3814 {
3815 /* next entry */
3816 Entry = Entry->Flink;
3817 continue;
3818 }
3819
3820 /* get text metrics */
3821 OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3822 if (OtmSize > OldOtmSize)
3823 {
3824 if (Otm)
3825 ExFreePoolWithTag(Otm, GDITAG_TEXT);
3826 Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
3827 }
3828
3829 /* update FontObj if lowest penalty */
3830 if (Otm)
3831 {
3832 IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
3833 TM = &Otm->otmTextMetrics;
3834 OldOtmSize = OtmSize;
3835
3836 /* create full name */
3837 pb = (LPBYTE)Otm + (WORD)(DWORD_PTR)Otm->otmpFullName;
3838 Status = RtlCreateUnicodeString(&FullFaceNameW, (LPWSTR)pb);
3839 if (!NT_SUCCESS(Status))
3840 {
3841 RtlFreeUnicodeString(&ActualNameW);
3842 RtlFreeUnicodeString(&FullFaceNameW);
3843 /* next entry */
3844 Entry = Entry->Flink;
3845 continue;
3846 }
3847
3848 Penalty = GetFontPenalty(LogFont, pRequestedNameW, &ActualNameW,
3849 &FullFaceNameW, FontGDI, Otm, TM,
3850 Face->style_name);
3851 if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
3852 {
3853 DPRINT("%ls Penalty: %lu\n", FullFaceNameW.Buffer, Penalty);
3854 RtlFreeUnicodeString(pActualNameW);
3855 RtlCreateUnicodeString(pActualNameW, ActualNameW.Buffer);
3856
3857 *FontObj = GDIToObj(FontGDI, FONT);
3858 *MatchPenalty = Penalty;
3859 }
3860
3861 RtlFreeUnicodeString(&FullFaceNameW);
3862 }
3863
3864 /* free strings */
3865 RtlFreeUnicodeString(&ActualNameW);
3866
3867 /* next entry */
3868 Entry = Entry->Flink;
3869 }
3870
3871 if (Otm)
3872 ExFreePoolWithTag(Otm, GDITAG_TEXT);
3873 }
3874
3875 static
3876 VOID
3877 FASTCALL
3878 IntFontType(PFONTGDI Font)
3879 {
3880 PS_FontInfoRec psfInfo;
3881 FT_ULong tmp_size = 0;
3882 FT_Face Face = Font->SharedFace->Face;
3883
3884 if (FT_HAS_MULTIPLE_MASTERS(Face))
3885 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
3886 if (FT_HAS_VERTICAL(Face))
3887 Font->FontObj.flFontType |= FO_VERT_FACE;
3888 if (!FT_IS_SCALABLE(Face))
3889 Font->FontObj.flFontType |= FO_TYPE_RASTER;
3890 if (FT_IS_SFNT(Face))
3891 {
3892 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
3893 if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
3894 Font->FontObj.flFontType |= FO_POSTSCRIPT;
3895 }
3896 if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
3897 {
3898 Font->FontObj.flFontType |= FO_POSTSCRIPT;
3899 }
3900 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
3901 if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
3902 {
3903 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
3904 }
3905 }
3906
3907 NTSTATUS
3908 FASTCALL
3909 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
3910 {
3911 NTSTATUS Status = STATUS_SUCCESS;
3912 PTEXTOBJ TextObj;
3913 UNICODE_STRING ActualNameW, RequestedNameW;
3914 PPROCESSINFO Win32Process;
3915 ULONG MatchPenalty;
3916 LOGFONTW *pLogFont;
3917 FT_Face Face;
3918
3919 if (!pTextObj)
3920 {
3921 TextObj = TEXTOBJ_LockText(FontHandle);
3922 if (NULL == TextObj)
3923 {
3924 return STATUS_INVALID_HANDLE;
3925 }
3926
3927 if (TextObj->fl & TEXTOBJECT_INIT)
3928 {
3929 TEXTOBJ_UnlockText(TextObj);
3930 return STATUS_SUCCESS;
3931 }
3932 }
3933 else
3934 {
3935 TextObj = pTextObj;
3936 }
3937
3938 RtlInitUnicodeString(&ActualNameW, NULL);
3939
3940 pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
3941 if (! RtlCreateUnicodeString(&RequestedNameW, pLogFont->lfFaceName))
3942 {
3943 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
3944 return STATUS_NO_MEMORY;
3945 }
3946
3947 DPRINT("Font '%ls' is substituted by: ", RequestedNameW.Buffer);
3948 SubstituteFontName(&RequestedNameW);
3949 DPRINT("'%ls'.\n", RequestedNameW.Buffer);
3950
3951 MatchPenalty = 0xFFFFFFFF;
3952 TextObj->Font = NULL;
3953
3954 Win32Process = PsGetCurrentProcessWin32Process();
3955
3956 /* Search private fonts */
3957 IntLockProcessPrivateFonts(Win32Process);
3958 FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont,
3959 &RequestedNameW, &ActualNameW,
3960 &Win32Process->PrivateFontListHead);
3961 IntUnLockProcessPrivateFonts(Win32Process);
3962
3963 /* Search system fonts */
3964 IntLockGlobalFonts;
3965 FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont,
3966 &RequestedNameW, &ActualNameW,
3967 &FontListHead);
3968 IntUnLockGlobalFonts;
3969
3970 if (NULL == TextObj->Font)
3971 {
3972 DPRINT1("Request font %S not found, no fonts loaded at all\n",
3973 pLogFont->lfFaceName);
3974 Status = STATUS_NOT_FOUND;
3975 }
3976 else
3977 {
3978 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
3979 // Need hdev, when freetype is loaded need to create DEVOBJ for
3980 // Consumer and Producer.
3981 TextObj->Font->iUniq = 1; // Now it can be cached.
3982 IntFontType(FontGdi);
3983 FontGdi->flType = TextObj->Font->flFontType;
3984 FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
3985 FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
3986 FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
3987 if (pLogFont->lfWeight != FW_DONTCARE)
3988 FontGdi->RequestWeight = pLogFont->lfWeight;
3989 else
3990 FontGdi->RequestWeight = FW_NORMAL;
3991
3992 Face = FontGdi->SharedFace->Face;
3993
3994 //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name);
3995
3996 if (!FontGdi->OriginalItalic)
3997 FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name);
3998
3999 TextObj->fl |= TEXTOBJECT_INIT;
4000 Status = STATUS_SUCCESS;
4001
4002 DPRINT("RequestedNameW: %ls (CharSet: %d) -> ActualNameW: %ls (CharSet: %d)\n",
4003 RequestedNameW.Buffer, pLogFont->lfCharSet,
4004 ActualNameW.Buffer, FontGdi->CharSet);
4005 }
4006
4007 RtlFreeUnicodeString(&RequestedNameW);
4008 RtlFreeUnicodeString(&ActualNameW);
4009 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
4010
4011 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
4012
4013 return Status;
4014 }
4015
4016
4017 static
4018 BOOL
4019 FASTCALL
4020 IntGetFullFileName(
4021 POBJECT_NAME_INFORMATION NameInfo,
4022 ULONG Size,
4023 PUNICODE_STRING FileName)
4024 {
4025 NTSTATUS Status;
4026 OBJECT_ATTRIBUTES ObjectAttributes;
4027 HANDLE hFile;
4028 IO_STATUS_BLOCK IoStatusBlock;
4029 ULONG Desired;
4030
4031 InitializeObjectAttributes(&ObjectAttributes,
4032 FileName,
4033 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
4034 NULL,
4035 NULL);
4036
4037 Status = ZwOpenFile(
4038 &hFile,
4039 0, // FILE_READ_ATTRIBUTES,
4040 &ObjectAttributes,
4041 &IoStatusBlock,
4042 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4043 0);
4044
4045 if (!NT_SUCCESS(Status))
4046 {
4047 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
4048 return FALSE;
4049 }
4050
4051 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
4052 ZwClose(hFile);
4053 if (!NT_SUCCESS(Status))
4054 {
4055 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
4056 return FALSE;
4057 }
4058
4059 return TRUE;
4060 }
4061
4062 static BOOL
4063 EqualFamilyInfo(FONTFAMILYINFO *pInfo1, FONTFAMILYINFO *pInfo2)
4064 {
4065 UNICODE_STRING Str1, Str2;
4066 ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
4067 ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
4068 RtlInitUnicodeString(&Str1, pLog1->elfLogFont.lfFaceName);
4069 RtlInitUnicodeString(&Str2, pLog2->elfLogFont.lfFaceName);
4070 if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE))
4071 {
4072 return FALSE;
4073 }
4074 if ((pLog1->elfStyle != NULL) != (pLog2->elfStyle != NULL))
4075 return FALSE;
4076 if (pLog1->elfStyle != NULL)
4077 {
4078 RtlInitUnicodeString(&Str1, pLog1->elfStyle);
4079 RtlInitUnicodeString(&Str2, pLog2->elfStyle);
4080 if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE))
4081 {
4082 return FALSE;
4083 }
4084 }
4085 return TRUE;
4086 }
4087
4088 static VOID
4089 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
4090 {
4091 wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
4092 if (FamInfo->EnumLogFontEx.elfStyle[0] &&
4093 _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
4094 {
4095 wcscat(psz, L" ");
4096 wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
4097 }
4098 }
4099
4100 BOOL
4101 FASTCALL
4102 IntGdiGetFontResourceInfo(
4103 PUNICODE_STRING FileName,
4104 PVOID pBuffer,
4105 DWORD *pdwBytes,
4106 DWORD dwType)
4107 {
4108 UNICODE_STRING EntryFileName;
4109 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
4110 PLIST_ENTRY ListEntry;
4111 PFONT_ENTRY FontEntry;
4112 ULONG Size, i, Count;
4113 LPBYTE pbBuffer;
4114 BOOL IsEqual;
4115 FONTFAMILYINFO *FamInfo;
4116 const ULONG MaxFamInfo = 64;
4117 BOOL bSuccess;
4118
4119 DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
4120
4121 /* Create buffer for full path name */
4122 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
4123 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4124 if (!NameInfo1)
4125 {
4126 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4127 return FALSE;
4128 }
4129
4130 /* Get the full path name */
4131 if (!IntGetFullFileName(NameInfo1, Size, FileName))
4132 {
4133 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4134 return FALSE;
4135 }
4136
4137 /* Create a buffer for the entries' names */
4138 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
4139 if (!NameInfo2)
4140 {
4141 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4142 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4143 return FALSE;
4144 }
4145
4146 FamInfo = ExAllocatePoolWithTag(PagedPool,
4147 sizeof(FONTFAMILYINFO) * MaxFamInfo,
4148 TAG_FINF);
4149 if (!FamInfo)
4150 {
4151 ExFreePoolWithTag(NameInfo2, TAG_FINF);
4152 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4153 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4154 return FALSE;
4155 }
4156 /* Try to find the pathname in the global font list */
4157 Count = 0;
4158 IntLockGlobalFonts;
4159 for (ListEntry = FontListHead.Flink; ListEntry != &FontListHead;
4160 ListEntry = ListEntry->Flink)
4161 {
4162 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
4163 if (FontEntry->Font->Filename == NULL)
4164 continue;
4165
4166 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
4167 if (!IntGetFullFileName(NameInfo2, Size, &EntryFileName))
4168 continue;
4169
4170 if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
4171 continue;
4172
4173 IsEqual = FALSE;
4174 FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
4175 FontEntry->Font);
4176 for (i = 0; i < Count; ++i)
4177 {
4178 if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
4179 {
4180 IsEqual = TRUE;
4181 break;
4182 }
4183 }
4184 if (!IsEqual)
4185 {
4186 /* Found */
4187 ++Count;
4188 if (Count >= MaxFamInfo)
4189 break;
4190 }
4191 }
4192 IntUnLockGlobalFonts;
4193
4194 /* Free the buffers */
4195 ExFreePoolWithTag(NameInfo1, TAG_FINF);
4196 ExFreePool(NameInfo2);
4197
4198 if (Count == 0 && dwType != 5)
4199 {
4200 /* Font could not be found in system table
4201 dwType == 5 will still handle this */
4202 ExFreePoolWithTag(FamInfo, TAG_FINF);
4203 return FALSE;
4204 }
4205
4206 bSuccess = FALSE;
4207 switch (dwType)
4208 {
4209 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
4210 Size = sizeof(DWORD);
4211 if (*pdwBytes == 0)
4212 {
4213 *pdwBytes = Size;
4214 bSuccess = TRUE;
4215 }
4216 else if (pBuffer)
4217 {
4218 if (*pdwBytes >= Size)
4219 {
4220 *(DWORD*)pBuffer = Count;
4221 }
4222 *pdwBytes = Size;
4223 bSuccess = TRUE;
4224 }
4225 break;
4226
4227 case 1: /* copy the font title */
4228 /* calculate the required size */
4229 Size = 0;
4230 Size += wcslen(FamInfo[0].EnumLogFontEx.elfLogFont.lfFaceName);
4231 if (FamInfo[0].EnumLogFontEx.elfStyle[0] &&
4232 _wcsicmp(FamInfo[0].EnumLogFontEx.elfStyle, L"Regular") != 0)
4233 {
4234 Size += 1 + wcslen(FamInfo[0].EnumLogFontEx.elfStyle);
4235 }
4236 for (i = 1; i < Count; ++i)
4237 {
4238 Size += 3; /* " & " */
4239 Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
4240 if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
4241 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
4242 {
4243 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
4244 }
4245 }
4246 Size += 2; /* "\0\0" */
4247 Size *= sizeof(WCHAR);
4248
4249 if (*pdwBytes == 0)
4250 {
4251 *pdwBytes = Size;
4252 bSuccess = TRUE;
4253 }
4254 else if (pBuffer)
4255 {
4256 if (*pdwBytes >= Size)
4257 {
4258 /* store font title to buffer */
4259 WCHAR *psz = pBuffer;
4260 *psz = 0;
4261 IntAddNameFromFamInfo(psz, &FamInfo[0]);
4262 for (i = 1; i < Count; ++i)
4263 {
4264 wcscat(psz, L" & ");
4265 IntAddNameFromFamInfo(psz, &FamInfo[i]);
4266 }
4267 psz[wcslen(psz) + 1] = UNICODE_NULL;
4268 *pdwBytes = Size;
4269 bSuccess = TRUE;
4270 }
4271 else
4272 {
4273 *pdwBytes = 1024; /* this is confirmed value */
4274 }
4275 }
4276 break;
4277
4278 case 2: /* Copy an array of LOGFONTW */
4279 Size = Count * sizeof(LOGFONTW);
4280 if (*pdwBytes == 0)
4281 {
4282 *pdwBytes = Size;
4283 bSuccess = TRUE;
4284 }
4285 else if (pBuffer)
4286 {
4287 if (*pdwBytes >= Size)
4288 {
4289 pbBuffer = (LPBYTE)pBuffer;
4290 for (i = 0; i < Count; ++i)
4291 {
4292 FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
4293 RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
4294 pbBuffer += sizeof(LOGFONTW);
4295 }
4296 }
4297 *pdwBytes = Size;
4298 bSuccess = TRUE;
4299 }
4300 else
4301 {
4302 *pdwBytes = 1024; /* this is confirmed value */
4303 }
4304 break;
4305
4306 case 3:
4307 Size = sizeof(DWORD);
4308 if (*pdwBytes == 0)
4309 {
4310 *pdwBytes = Size;
4311 bSuccess = TRUE;
4312 }
4313 else if (pBuffer)
4314 {
4315 if (*pdwBytes >= Size)
4316 {
4317 /* FIXME: What exactly is copied here? */
4318 *(DWORD*)pBuffer = 1;
4319 }
4320 *pdwBytes = Size;
4321 bSuccess = TRUE;
4322 }
4323 break;
4324
4325 case 4: /* full file path */
4326 if (FileName->Length >= 4 * sizeof(WCHAR))
4327 {
4328 /* The beginning of FileName is \??\ */
4329 LPWSTR pch = FileName->Buffer + 4;
4330 DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
4331
4332 Size = Length + sizeof(WCHAR);
4333 if (*pdwBytes == 0)
4334 {
4335 *pdwBytes = Size;
4336 bSuccess = TRUE;
4337 }
4338 else if (pBuffer)
4339 {
4340 if (*pdwBytes >= Size)
4341 {
4342 RtlCopyMemory(pBuffer, pch, Size);
4343 }
4344 *pdwBytes = Size;
4345 bSuccess = TRUE;
4346 }
4347 }
4348 break;
4349
4350 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
4351 Size = sizeof(BOOL);
4352 if (*pdwBytes == 0)
4353 {
4354 *pdwBytes = Size;
4355 bSuccess = TRUE;
4356 }
4357 else if (pBuffer)
4358 {
4359 if (*pdwBytes >= Size)
4360 {
4361 *(BOOL*)pBuffer = Count == 0;
4362 }
4363 *pdwBytes = Size;
4364 bSuccess = TRUE;
4365 }
4366 break;
4367 }
4368 ExFreePoolWithTag(FamInfo, TAG_FINF);
4369
4370 return bSuccess;
4371 }
4372
4373
4374 BOOL
4375 FASTCALL
4376 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
4377 {
4378 if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
4379 Info->iTechnology = RI_TECH_BITMAP;
4380 else
4381 {
4382 if (FT_IS_SCALABLE(Font->SharedFace->Face))
4383 Info->iTechnology = RI_TECH_SCALABLE;
4384 else
4385 Info->iTechnology = RI_TECH_FIXED;
4386 }
4387 Info->iUniq = Font->FontObj.iUniq;
4388 Info->dwUnknown = -1;
4389 return TRUE;
4390 }
4391
4392
4393 DWORD
4394 FASTCALL
4395 ftGdiGetKerningPairs( PFONTGDI Font,
4396 DWORD cPairs,
4397 LPKERNINGPAIR pKerningPair)
4398 {
4399 DWORD Count = 0;
4400 INT i = 0;
4401 FT_Face face = Font->SharedFace->Face;
4402
4403 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
4404 {
4405 FT_UInt previous_index = 0, glyph_index = 0;
4406 FT_ULong char_code, char_previous;
4407 FT_Vector delta;
4408
4409 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
4410
4411 IntLockFreeType;
4412
4413 while (glyph_index)
4414 {
4415 if (previous_index && glyph_index)
4416 {
4417 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
4418
4419 if (pKerningPair && cPairs)
4420 {
4421 pKerningPair[i].wFirst = char_previous;
4422 pKerningPair[i].wSecond = char_code;
4423 pKerningPair[i].iKernAmount = delta.x;
4424 i++;
4425 if (i == cPairs) break;
4426 }
4427 Count++;
4428 }
4429 previous_index = glyph_index;
4430 char_previous = char_code;
4431 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
4432 }
4433 IntUnLockFreeType;
4434 }
4435 return Count;
4436 }
4437
4438
4439 ///////////////////////////////////////////////////////////////////////////
4440 //
4441 // Functions needing sorting.
4442 //
4443 ///////////////////////////////////////////////////////////////////////////
4444 int APIENTRY
4445 NtGdiGetFontFamilyInfo(HDC Dc,
4446 LPLOGFONTW UnsafeLogFont,
4447 PFONTFAMILYINFO UnsafeInfo,
4448 DWORD Size)
4449 {
4450 NTSTATUS Status;
4451 LOGFONTW LogFont;
4452 PFONTFAMILYINFO Info;
4453 DWORD Count;
4454 PPROCESSINFO Win32Process;
4455
4456 /* Make a safe copy */
4457 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
4458 if (! NT_SUCCESS(Status))
4459 {
4460 EngSetLastError(ERROR_INVALID_PARAMETER);
4461 return -1;
4462 }
4463
4464 /* Allocate space for a safe copy */
4465 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT);
4466 if (NULL == Info)
4467 {
4468 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4469 return -1;
4470 }
4471
4472 /* Enumerate font families in the global list */
4473 IntLockGlobalFonts;
4474 Count = 0;
4475 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
4476 {
4477 IntUnLockGlobalFonts;
4478 ExFreePoolWithTag(Info, GDITAG_TEXT);
4479 return -1;
4480 }
4481 IntUnLockGlobalFonts;
4482
4483 /* Enumerate font families in the process local list */
4484 Win32Process = PsGetCurrentProcessWin32Process();
4485 IntLockProcessPrivateFonts(Win32Process);
4486 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
4487 &Win32Process->PrivateFontListHead))
4488 {
4489 IntUnLockProcessPrivateFonts(Win32Process);
4490 ExFreePoolWithTag(Info, GDITAG_TEXT);
4491 return -1;
4492 }
4493 IntUnLockProcessPrivateFonts(Win32Process);
4494
4495 /* Enumerate font families in the registry */
4496 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
4497 {
4498 ExFreePoolWithTag(Info, GDITAG_TEXT);
4499 return -1;
4500 }
4501
4502 /* Return data to caller */
4503 if (0 != Count)
4504 {
4505 Status = MmCopyToCaller(UnsafeInfo, Info,
4506 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
4507 if (! NT_SUCCESS(Status))
4508 {
4509 ExFreePoolWithTag(Info, GDITAG_TEXT);
4510 EngSetLastError(ERROR_INVALID_PARAMETER);
4511 return -1;
4512 }
4513 }
4514
4515 ExFreePoolWithTag(Info, GDITAG_TEXT);
4516
4517 return Count;
4518 }
4519
4520 FORCEINLINE
4521 LONG
4522 ScaleLong(LONG lValue, PFLOATOBJ pef)
4523 {
4524 FLOATOBJ efTemp;
4525
4526 /* Check if we have scaling different from 1 */
4527 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
4528 {
4529 /* Need to multiply */
4530 FLOATOBJ_SetLong(&efTemp, lValue);
4531 FLOATOBJ_Mul(&efTemp, pef);
4532 lValue = FLOATOBJ_GetLong(&efTemp);
4533 }
4534
4535 return lValue;
4536 }
4537
4538 BOOL
4539 APIENTRY
4540 GreExtTextOutW(
4541 IN HDC hDC,
4542 IN INT XStart,
4543 IN INT YStart,
4544 IN UINT fuOptions,
4545 IN OPTIONAL PRECTL lprc,
4546 IN LPCWSTR String,
4547 IN INT Count,
4548 IN OPTIONAL LPINT Dx,
4549 IN DWORD dwCodePage)
4550 {
4551 /*
4552 * FIXME:
4553 * Call EngTextOut, which does the real work (calling DrvTextOut where
4554 * appropriate)
4555 */
4556
4557 DC *dc;
4558 PDC_ATTR pdcattr;
4559 SURFOBJ *SurfObj;
4560 SURFACE *psurf = NULL;
4561 int error, glyph_index, i;
4562 FT_Face face;
4563 FT_GlyphSlot glyph;
4564 FT_BitmapGlyph realglyph;
4565 LONGLONG TextLeft, RealXStart;
4566 ULONG TextTop, previous, BackgroundLeft;
4567 FT_Bool use_kerning;
4568 RECTL DestRect, MaskRect;
4569 POINTL SourcePoint, BrushOrigin;
4570 HBITMAP HSourceGlyph;
4571 SURFOBJ *SourceGlyphSurf;
4572 SIZEL bitSize;
4573 INT yoff;
4574 FONTOBJ *FontObj;
4575 PFONTGDI FontGDI;
4576 PTEXTOBJ TextObj = NULL;
4577 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
4578 FT_Render_Mode RenderMode;
4579 BOOLEAN Render;
4580 POINT Start;
4581 BOOL DoBreak = FALSE;
4582 USHORT DxShift;
4583 PMATRIX pmxWorldToDevice;
4584 LONG fixAscender, fixDescender;
4585 FLOATOBJ Scale;
4586 LOGFONTW *plf;
4587 BOOL EmuBold, EmuItalic;
4588 int thickness;
4589
4590 // TODO: Write test-cases to exactly match real Windows in different
4591 // bad parameters (e.g. does Windows check the DC or the RECT first?).
4592 dc = DC_LockDc(hDC);
4593 if (!dc)
4594 {
4595 EngSetLastError(ERROR_INVALID_HANDLE);
4596 return FALSE;
4597 }
4598 if (dc->dctype == DC_TYPE_INFO)
4599 {
4600 DC_UnlockDc(dc);
4601 /* Yes, Windows really returns TRUE in this case */
4602 return TRUE;
4603 }
4604
4605 pdcattr = dc->pdcattr;
4606
4607 if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE)
4608 {
4609 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
4610 DC_vUpdateBackgroundBrush(dc);
4611 }
4612
4613 /* Check if String is valid */
4614 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
4615 {
4616 EngSetLastError(ERROR_INVALID_PARAMETER);
4617 goto fail;
4618 }
4619
4620 DxShift = fuOptions & ETO_PDY ? 1 : 0;
4621
4622 if (PATH_IsPathOpen(dc->dclevel))
4623 {
4624 if (!PATH_ExtTextOut( dc,
4625 XStart,
4626 YStart,
4627 fuOptions,
4628 (const RECTL *)lprc,
4629 String,
4630 Count,
4631 (const INT *)Dx)) goto fail;
4632 goto good;
4633 }
4634
4635 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
4636 {
4637 IntLPtoDP(dc, (POINT *)lprc, 2);
4638 }
4639
4640 if(pdcattr->lTextAlign & TA_UPDATECP)
4641 {
4642 Start.x = pdcattr->ptlCurrent.x;
4643 Start.y = pdcattr->ptlCurrent.y;
4644 } else {
4645 Start.x = XStart;
4646 Start.y = YStart;
4647 IntLPtoDP(dc, &Start, 1);
4648 }
4649
4650 RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
4651 YStart = Start.y + dc->ptlDCOrig.y;
4652
4653 SourcePoint.x = 0;
4654 SourcePoint.y = 0;
4655 MaskRect.left = 0;
4656 MaskRect.top = 0;
4657 BrushOrigin.x = 0;
4658 BrushOrigin.y = 0;
4659
4660 if (!dc->dclevel.pSurface)
4661 {
4662 goto fail;
4663 }
4664
4665 if ((fuOptions & ETO_OPAQUE) && lprc)
4666 {
4667 DestRect.left = lprc->left;
4668 DestRect.top = lprc->top;
4669 DestRect.right = lprc->right;
4670 DestRect.bottom = lprc->bottom;
4671
4672 DestRect.left += dc->ptlDCOrig.x;
4673 DestRect.top += dc->ptlDCOrig.y;
4674 DestRect.right += dc->ptlDCOrig.x;
4675 DestRect.bottom += dc->ptlDCOrig.y;
4676
4677 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
4678 {
4679 IntUpdateBoundsRect(dc, &DestRect);
4680 }
4681
4682 DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL);
4683
4684 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
4685 DC_vUpdateBackgroundBrush(dc);
4686
4687 psurf = dc->dclevel.pSurface;
4688 IntEngBitBlt(
4689 &psurf->SurfObj,
4690 NULL,
4691 NULL,
4692 &dc->co.ClipObj,
4693 NULL,
4694 &DestRect,
4695 &SourcePoint,
4696 &SourcePoint,
4697 &dc->eboBackground.BrushObject,
4698 &BrushOrigin,
4699 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
4700 fuOptions &= ~ETO_OPAQUE;
4701 DC_vFinishBlit(dc, NULL);
4702 }
4703 else
4704 {
4705 if (pdcattr->jBkMode == OPAQUE)
4706 {
4707 fuOptions |= ETO_OPAQUE;
4708 }
4709 }
4710
4711 TextObj = RealizeFontInit(pdcattr->hlfntNew);
4712 if (TextObj == NULL)
4713 {
4714 goto fail;
4715 }
4716
4717 FontObj = TextObj->Font;
4718 ASSERT(FontObj);
4719 FontGDI = ObjToGDI(FontObj, FONT);
4720 ASSERT(FontGDI);
4721
4722 IntLockFreeType;
4723 face = FontGDI->SharedFace->Face;
4724
4725 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4726 EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
4727 EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
4728
4729 Render = IntIsFontRenderingEnabled();
4730 if (Render)
4731 RenderMode = IntGetFontRenderMode(plf);
4732 else
4733 RenderMode = FT_RENDER_MODE_MONO;
4734
4735 if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
4736 {
4737 IntUnLockFreeType;
4738 goto fail;
4739 }
4740
4741 if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
4742 {
4743 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
4744 FtSetCoordinateTransform(face, pmxWorldToDevice);
4745
4746 fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
4747 fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
4748 }
4749 else
4750 {
4751 pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
4752 FtSetCoordinateTransform(face, pmxWorldToDevice);
4753
4754 fixAscender = face->size->metrics.ascender;
4755 fixDescender = face->size->metrics.descender;
4756 }
4757
4758 /*
4759 * Process the vertical alignment and determine the yoff.
4760 */
4761
4762 if (pdcattr->lTextAlign & TA_BASELINE)
4763 yoff = 0;
4764 else if (pdcattr->lTextAlign & TA_BOTTOM)
4765 yoff = -fixDescender >> 6;
4766 else /* TA_TOP */
4767 yoff = fixAscender >> 6;
4768
4769 use_kerning = FT_HAS_KERNING(face);
4770 previous = 0;
4771
4772 /*
4773 * Process the horizontal alignment and modify XStart accordingly.
4774 */
4775
4776 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
4777 {
4778 ULONGLONG TextWidth = 0;
4779 LPCWSTR TempText = String;
4780 int iStart;
4781
4782 /*
4783 * Calculate width of the text.
4784 */
4785
4786 if (NULL != Dx)
4787 {
4788 iStart = Count < 2 ? 0 : Count - 2;
4789 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
4790 }
4791 else
4792 {
4793 iStart = 0;
4794 }
4795 TempText = String + iStart;
4796
4797 for (i = iStart; i < Count; i++)
4798 {
4799 if (fuOptions & ETO_GLYPH_INDEX)
4800 glyph_index = *TempText;
4801 else
4802 glyph_index = FT_Get_Char_Index(face, *TempText);
4803
4804 if (EmuBold || EmuItalic)
4805 realglyph = NULL;
4806 else
4807 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
4808 plf->lfHeight, pmxWorldToDevice);
4809 if (!realglyph)
4810 {
4811 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
4812 if (error)
4813 {
4814 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
4815 }
4816
4817 glyph = face->glyph;
4818 if (EmuBold || EmuItalic)
4819 {
4820 if (EmuBold)
4821 FT_GlyphSlot_Embolden(glyph);
4822 if (EmuItalic)
4823 FT_GlyphSlot_Oblique(glyph);
4824 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
4825 }
4826 else
4827 {
4828 realglyph = ftGdiGlyphCacheSet(face,
4829 glyph_index,
4830 plf->lfHeight,
4831 pmxWorldToDevice,
4832 glyph,
4833 RenderMode);
4834 }
4835 if (!realglyph)
4836 {
4837 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
4838 IntUnLockFreeType;
4839 goto fail;
4840 }
4841
4842 }
4843 /* Retrieve kerning distance */
4844 if (use_kerning && previous && glyph_index)
4845 {
4846 FT_Vector delta;
4847 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
4848 TextWidth += delta.x;
4849 }
4850
4851 TextWidth += realglyph->root.advance.x >> 10;
4852
4853 if (EmuBold || EmuItalic)
4854 {
4855 FT_Done_Glyph((FT_Glyph)realglyph);
4856 realglyph = NULL;
4857 }
4858
4859 previous = glyph_index;
4860 TempText++;
4861 }
4862
4863 previous = 0;
4864
4865 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
4866 {
4867 RealXStart -= TextWidth / 2;
4868 }
4869 else
4870 {
4871 RealXStart -= TextWidth;
4872 }
4873 }
4874
4875 /* Lock blit with a dummy rect */
4876 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
4877
4878 psurf = dc->dclevel.pSurface;
4879 SurfObj = &psurf->SurfObj ;
4880
4881 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
4882 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
4883
4884 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
4885 DC_vUpdateBackgroundBrush(dc) ;
4886
4887 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
4888 DC_vUpdateTextBrush(dc) ;
4889
4890 if (!face->units_per_EM)
4891 {
4892 thickness = 1;
4893 }
4894 else
4895 {
4896 thickness = face->underline_thickness *
4897 face->size->metrics.y_ppem / face->units_per_EM;
4898 if (thickness <= 0)
4899 thickness = 1;
4900 }
4901
4902 if ((fuOptions & ETO_OPAQUE) && plf->lfItalic)
4903 {
4904 /* Draw background */
4905 TextLeft = RealXStart;
4906 TextTop = YStart;
4907 BackgroundLeft = (RealXStart + 32) >> 6;
4908 for (i = 0; i < Count; ++i)
4909 {
4910 if (fuOptions & ETO_GLYPH_INDEX)
4911 glyph_index = String[i];
4912 else
4913 glyph_index = FT_Get_Char_Index(face, String[i]);
4914
4915 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
4916 if (error)
4917 {
4918 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
4919 IntUnLockFreeType;
4920 DC_vFinishBlit(dc, NULL);
4921 goto fail2;
4922 }
4923
4924 glyph = face->glyph;
4925 if (EmuBold)
4926 FT_GlyphSlot_Embolden(glyph);
4927 if (EmuItalic)
4928 FT_GlyphSlot_Oblique(glyph);
4929 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
4930 if (!realglyph)
4931 {
4932 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
4933 IntUnLockFreeType;
4934 DC_vFinishBlit(dc, NULL);
4935 goto fail2;
4936 }
4937
4938 /* retrieve kerning distance and move pen position */
4939 if (use_kerning && previous && glyph_index && NULL == Dx)
4940 {
4941 FT_Vector delta;
4942 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
4943 TextLeft += delta.x;
4944 }
4945 DPRINT("TextLeft: %I64d\n", TextLeft);
4946 DPRINT("TextTop: %lu\n", TextTop);
4947 DPRINT("Advance: %d\n", realglyph->root.advance.x);
4948
4949 DestRect.left = BackgroundLeft;
4950 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
4951 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
4952 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
4953 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
4954 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
4955 {
4956 IntUpdateBoundsRect(dc, &DestRect);
4957 }
4958 IntEngBitBlt(
4959 &psurf->SurfObj,
4960 NULL,
4961 NULL,
4962 &dc->co.ClipObj,
4963 NULL,
4964 &DestRect,
4965 &SourcePoint,
4966 &SourcePoint,
4967 &dc->eboBackground.BrushObject,
4968 &BrushOrigin,
4969 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
4970 MouseSafetyOnDrawEnd(dc->ppdev);
4971 BackgroundLeft = DestRect.right;
4972
4973 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
4974 DestRect.right = DestRect.left + realglyph->bitmap.width;
4975 DestRect.top = TextTop + yoff - realglyph->top;
4976 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
4977
4978 bitSize.cx = realglyph->bitmap.width;
4979 bitSize.cy = realglyph->bitmap.rows;
4980 MaskRect.right = realglyph->bitmap.width;
4981 MaskRect.bottom = realglyph->bitmap.rows;
4982
4983 if (NULL == Dx)
4984 {
4985 TextLeft += realglyph->root.advance.x >> 10;
4986 DPRINT("New TextLeft: %I64d\n", TextLeft);
4987 }
4988 else
4989 {
4990 // FIXME this should probably be a matrix transform with TextTop as well.
4991 Scale = pdcattr->mxWorldToDevice.efM11;
4992 if (FLOATOBJ_Equal0(&Scale))
4993 FLOATOBJ_Set1(&Scale);
4994
4995 /* do the shift before multiplying to preserve precision */
4996 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
4997 TextLeft += FLOATOBJ_GetLong(&Scale);
4998 DPRINT("New TextLeft2: %I64d\n", TextLeft);
4999 }
5000
5001 if (DxShift)
5002 {
5003 TextTop -= Dx[2 * i + 1] << 6;
5004 }
5005
5006 previous = glyph_index;
5007
5008 if (EmuBold || EmuItalic)
5009 {
5010 FT_Done_Glyph((FT_Glyph)realglyph);
5011 realglyph = NULL;
5012 }
5013 }
5014 }
5015
5016 /*
5017 * The main rendering loop.
5018 */
5019 TextLeft = RealXStart;
5020 TextTop = YStart;
5021 BackgroundLeft = (RealXStart + 32) >> 6;
5022 for (i = 0; i < Count; ++i)
5023 {
5024 if (fuOptions & ETO_GLYPH_INDEX)
5025 glyph_index = String[i];
5026 else
5027 glyph_index = FT_Get_Char_Index(face, String[i]);
5028
5029 if (EmuBold || EmuItalic)
5030 realglyph = NULL;
5031 else
5032 realglyph = ftGdiGlyphCacheGet(face, glyph_index,
5033 plf->lfHeight, pmxWorldToDevice);
5034 if (!realglyph)
5035 {
5036 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5037 if (error)
5038 {
5039 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
5040 IntUnLockFreeType;
5041 DC_vFinishBlit(dc, NULL);
5042 goto fail2;
5043 }
5044
5045 glyph = face->glyph;
5046 if (EmuBold || EmuItalic)
5047 {
5048 if (EmuBold)
5049 FT_GlyphSlot_Embolden(glyph);
5050 if (EmuItalic)
5051 FT_GlyphSlot_Oblique(glyph);
5052 realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
5053 }
5054 else
5055 {
5056 realglyph = ftGdiGlyphCacheSet(face,
5057 glyph_index,
5058 plf->lfHeight,
5059 pmxWorldToDevice,
5060 glyph,
5061 RenderMode);
5062 }
5063 if (!realglyph)
5064 {
5065 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
5066 IntUnLockFreeType;
5067 DC_vFinishBlit(dc, NULL);
5068 goto fail2;
5069 }
5070 }
5071
5072 /* retrieve kerning distance and move pen position */
5073 if (use_kerning && previous && glyph_index && NULL == Dx)
5074 {
5075 FT_Vector delta;
5076 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
5077 TextLeft += delta.x;
5078 }
5079 DPRINT("TextLeft: %I64d\n", TextLeft);
5080 DPRINT("TextTop: %lu\n", TextTop);
5081 DPRINT("Advance: %d\n", realglyph->root.advance.x);
5082
5083 if ((fuOptions & ETO_OPAQUE) && !plf->lfItalic)
5084 {
5085 DestRect.left = BackgroundLeft;
5086 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
5087 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
5088 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
5089 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5090 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
5091 {
5092 IntUpdateBoundsRect(dc, &DestRect);
5093 }
5094 IntEngBitBlt(
5095 &psurf->SurfObj,
5096 NULL,
5097 NULL,
5098 &dc->co.ClipObj,
5099 NULL,
5100 &DestRect,
5101 &SourcePoint,
5102 &SourcePoint,
5103 &dc->eboBackground.BrushObject,
5104 &BrushOrigin,
5105 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
5106 MouseSafetyOnDrawEnd(dc->ppdev);
5107 BackgroundLeft = DestRect.right;
5108 }
5109
5110 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
5111 DestRect.right = DestRect.left + realglyph->bitmap.width;
5112 DestRect.top = TextTop + yoff - realglyph->top;
5113 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
5114
5115 bitSize.cx = realglyph->bitmap.width;
5116 bitSize.cy = realglyph->bitmap.rows;
5117 MaskRect.right = realglyph->bitmap.width;
5118 MaskRect.bottom = realglyph->bitmap.rows;
5119
5120 /* Check if the bitmap has any pixels */
5121 if ((bitSize.cx != 0) && (bitSize.cy != 0))
5122 {
5123 /*
5124 * We should create the bitmap out of the loop at the biggest possible
5125 * glyph size. Then use memset with 0 to clear it and sourcerect to
5126 * limit the work of the transbitblt.
5127 */
5128 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
5129 BMF_8BPP, BMF_TOPDOWN,
5130 realglyph->bitmap.buffer);
5131 if ( !HSourceGlyph )
5132 {
5133 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
5134 // FT_Done_Glyph(realglyph);
5135 IntUnLockFreeType;
5136 DC_vFinishBlit(dc, NULL);
5137 goto fail2;
5138 }
5139 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
5140 if ( !SourceGlyphSurf )
5141 {
5142 EngDeleteSurface((HSURF)HSourceGlyph);
5143 DPRINT1("WARNING: EngLockSurface() failed!\n");
5144 IntUnLockFreeType;
5145 DC_vFinishBlit(dc, NULL);
5146 goto fail2;
5147 }
5148
5149 /*
5150 * Use the font data as a mask to paint onto the DCs surface using a
5151 * brush.
5152 */
5153 if (lprc && (fuOptions & ETO_CLIPPED) &&
5154 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
5155 {
5156 // We do the check '>=' instead of '>' to possibly save an iteration
5157 // through this loop, since it's breaking after the drawing is done,
5158 // and x is always incremented.
5159 DestRect.right = lprc->right + dc->ptlDCOrig.x;
5160 DoBreak = TRUE;
5161 }
5162 if (lprc && (fuOptions & ETO_CLIPPED) &&
5163 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
5164 {
5165 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
5166 }
5167 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
5168 if (!IntEngMaskBlt(
5169 SurfObj,
5170 SourceGlyphSurf,
5171 &dc->co.ClipObj,
5172 &exloRGB2Dst.xlo,
5173 &exloDst2RGB.xlo,
5174 &DestRect,
5175 (PPOINTL)&MaskRect,
5176 &dc->eboText.BrushObject,
5177 &BrushOrigin))
5178 {
5179 DPRINT1("Failed to MaskBlt a glyph!\n");
5180 }
5181
5182 MouseSafetyOnDrawEnd(dc->ppdev) ;
5183
5184 EngUnlockSurface(SourceGlyphSurf);
5185 EngDeleteSurface((HSURF)HSourceGlyph);
5186 }
5187
5188 if (DoBreak)
5189 {
5190 break;
5191 }
5192
5193 if (plf->lfUnderline)
5194 {
5195 int i, position;
5196 if (!face->units_per_EM)
5197 {
5198 position = 0;
5199 }
5200 else
5201 {
5202 position = face->underline_position *
5203 face->size->metrics.y_ppem / face->units_per_EM;
5204 }
5205 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5206 {
5207 EngLineTo(SurfObj,
5208 &dc->co.ClipObj,
5209 &dc->eboText.BrushObject,
5210 (TextLeft >> 6),
5211 TextTop + yoff - position + i,
5212 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5213 TextTop + yoff - position + i,
5214 NULL,
5215 ROP2_TO_MIX(R2_COPYPEN));
5216 }
5217 }
5218 if (plf->lfStrikeOut)
5219 {
5220 int i;
5221 for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
5222 {
5223 EngLineTo(SurfObj,
5224 &dc->co.ClipObj,
5225 &dc->eboText.BrushObject,
5226 (TextLeft >> 6),
5227 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5228 ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
5229 TextTop + yoff - (fixAscender >> 6) / 3 + i,
5230 NULL,
5231 ROP2_TO_MIX(R2_COPYPEN));
5232 }
5233 }
5234
5235 if (NULL == Dx)
5236 {
5237 TextLeft += realglyph->root.advance.x >> 10;
5238 DPRINT("New TextLeft: %I64d\n", TextLeft);
5239 }
5240 else
5241 {
5242 // FIXME this should probably be a matrix transform with TextTop as well.
5243 Scale = pdcattr->mxWorldToDevice.efM11;
5244 if (FLOATOBJ_Equal0(&Scale))
5245 FLOATOBJ_Set1(&Scale);
5246
5247 /* do the shift before multiplying to preserve precision */
5248 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6);
5249 TextLeft += FLOATOBJ_GetLong(&Scale);
5250 DPRINT("New TextLeft2: %I64d\n", TextLeft);
5251 }
5252
5253 if (DxShift)
5254 {
5255 TextTop -= Dx[2 * i + 1] << 6;
5256 }
5257
5258 previous = glyph_index;
5259
5260 if (EmuBold || EmuItalic)
5261 {
5262 FT_Done_Glyph((FT_Glyph)realglyph);
5263 realglyph = NULL;
5264 }
5265 }
5266
5267 if (pdcattr->lTextAlign & TA_UPDATECP) {
5268 pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
5269 }
5270
5271 IntUnLockFreeType;
5272
5273 DC_vFinishBlit(dc, NULL) ;
5274
5275 EXLATEOBJ_vCleanup(&exloRGB2Dst);
5276 EXLATEOBJ_vCleanup(&exloDst2RGB);
5277 if (TextObj != NULL)
5278 TEXTOBJ_UnlockText(TextObj);
5279 good:
5280 DC_UnlockDc( dc );
5281
5282 return TRUE;
5283
5284 fail2:
5285 EXLATEOBJ_vCleanup(&exloRGB2Dst);
5286 EXLATEOBJ_vCleanup(&exloDst2RGB);
5287 fail:
5288 if (TextObj != NULL)
5289 TEXTOBJ_UnlockText(TextObj);
5290
5291 DC_UnlockDc(dc);
5292
5293 return FALSE;
5294 }
5295
5296 #define STACK_TEXT_BUFFER_SIZE 100
5297 BOOL
5298 APIENTRY
5299 NtGdiExtTextOutW(
5300 IN HDC hDC,
5301 IN INT XStart,
5302 IN INT YStart,
5303 IN UINT fuOptions,
5304 IN OPTIONAL LPRECT UnsafeRect,
5305 IN LPWSTR UnsafeString,
5306 IN INT Count,
5307 IN OPTIONAL LPINT UnsafeDx,
5308 IN DWORD dwCodePage)
5309 {
5310 BOOL Result = FALSE;
5311 NTSTATUS Status = STATUS_SUCCESS;
5312 RECTL SafeRect;
5313 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
5314 PVOID Buffer = LocalBuffer;
5315 LPCWSTR SafeString = NULL;
5316 LPINT SafeDx = NULL;
5317 ULONG BufSize, StringSize, DxSize = 0;
5318
5319 /* Check if String is valid */
5320 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
5321 {
5322 EngSetLastError(ERROR_INVALID_PARAMETER);
5323 return FALSE;
5324 }
5325
5326 if (Count > 0)
5327 {
5328 /* Calculate buffer size for string and Dx values */
5329 BufSize = StringSize = Count * sizeof(WCHAR);
5330 if (UnsafeDx)
5331 {
5332 /* If ETO_PDY is specified, we have pairs of INTs */
5333 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
5334 BufSize += DxSize;
5335 }
5336
5337 /* Check if our local buffer is large enough */
5338 if (BufSize > STACK_TEXT_BUFFER_SIZE)
5339 {
5340 /* It's not, allocate a temp buffer */
5341 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
5342 if (!Buffer)
5343 {
5344 return FALSE;
5345 }
5346 }
5347
5348 /* Probe and copy user mode data to the buffer */
5349 _SEH2_TRY
5350 {
5351 /* Put the Dx before the String to assure alignment of 4 */
5352 SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
5353
5354 /* Probe and copy the string */
5355 ProbeForRead(UnsafeString, StringSize, 1);
5356 memcpy((PVOID)SafeString, UnsafeString, StringSize);
5357
5358 /* If we have Dx values... */
5359 if (UnsafeDx)
5360 {
5361 /* ... probe and copy them */
5362 SafeDx = Buffer;
5363 ProbeForRead(UnsafeDx, DxSize, 1);
5364 memcpy(SafeDx, UnsafeDx, DxSize);
5365 }
5366 }
5367 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5368 {
5369 Status = _SEH2_GetExceptionCode();
5370 }
5371 _SEH2_END
5372 if (!NT_SUCCESS(Status))
5373 {
5374 goto cleanup;
5375 }
5376 }
5377
5378 /* If we have a rect, copy it */
5379 if (UnsafeRect)
5380 {
5381 _SEH2_TRY
5382 {
5383 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
5384 SafeRect = *UnsafeRect;
5385 }
5386 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5387 {
5388 Status = _SEH2_GetExceptionCode();
5389 }
5390 _SEH2_END
5391 if (!NT_SUCCESS(Status))
5392 {
5393 goto cleanup;
5394 }
5395 }
5396
5397 /* Finally call the internal routine */
5398 Result = GreExtTextOutW(hDC,
5399 XStart,
5400 YStart,
5401 fuOptions,
5402 &SafeRect,
5403 SafeString,
5404 Count,
5405 SafeDx,
5406 dwCodePage);
5407
5408 cleanup:
5409 /* If we allocated a buffer, free it */
5410 if (Buffer != LocalBuffer)
5411 {
5412 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
5413 }
5414
5415 return Result;
5416 }
5417
5418
5419 /*
5420 * @implemented
5421 */
5422 BOOL
5423 APIENTRY
5424 NtGdiGetCharABCWidthsW(
5425 IN HDC hDC,
5426 IN UINT FirstChar,
5427 IN ULONG Count,
5428 IN OPTIONAL PWCHAR UnSafepwch,
5429 IN FLONG fl,
5430 OUT PVOID Buffer)
5431 {
5432 LPABC SafeBuff;
5433 LPABCFLOAT SafeBuffF = NULL;
5434 PDC dc;
5435 PDC_ATTR pdcattr;
5436 PTEXTOBJ TextObj;
5437 PFONTGDI FontGDI;
5438 FT_Face face;
5439 FT_CharMap charmap, found = NULL;
5440 UINT i, glyph_index, BufferSize;
5441 HFONT hFont = 0;
5442 NTSTATUS Status = STATUS_SUCCESS;
5443 PMATRIX pmxWorldToDevice;
5444 PWCHAR Safepwch = NULL;
5445 LOGFONTW *plf;
5446
5447 if (!Buffer)
5448 {
5449 EngSetLastError(ERROR_INVALID_PARAMETER);
5450 return FALSE;
5451 }
5452
5453 if (UnSafepwch)
5454 {
5455 UINT pwchSize = Count * sizeof(WCHAR);
5456 Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
5457
5458 if(!Safepwch)
5459 {
5460 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5461 return FALSE;
5462 }
5463
5464 _SEH2_TRY
5465 {
5466 ProbeForRead(UnSafepwch, pwchSize, 1);
5467 RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
5468 }
5469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5470 {
5471 Status = _SEH2_GetExceptionCode();
5472 }
5473 _SEH2_END;
5474 }
5475
5476 if (!NT_SUCCESS(Status))
5477 {
5478 if(Safepwch)
5479 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
5480
5481 EngSetLastError(Status);
5482 return FALSE;
5483 }
5484
5485 BufferSize = Count * sizeof(ABC); // Same size!
5486 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
5487 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
5488 if (SafeBuff == NULL)
5489 {
5490
5491 if(Safepwch)
5492 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
5493
5494 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5495 return FALSE;
5496 }
5497
5498 dc = DC_LockDc(hDC);
5499 if (dc == NULL)
5500 {
5501 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
5502
5503 if(Safepwch)
5504 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
5505
5506 EngSetLastError(ERROR_INVALID_HANDLE);
5507 return FALSE;
5508 }
5509 pdcattr = dc->pdcattr;
5510 hFont = pdcattr->hlfntNew;
5511 TextObj = RealizeFontInit(hFont);
5512
5513 /* Get the DC's world-to-device transformation matrix */
5514 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
5515 DC_UnlockDc(dc);
5516
5517 if (TextObj == NULL)
5518 {
5519 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
5520
5521 if(Safepwch)
5522 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
5523
5524 EngSetLastError(ERROR_INVALID_HANDLE);
5525 return FALSE;
5526 }
5527
5528 FontGDI = ObjToGDI(TextObj->Font, FONT);
5529
5530 face = FontGDI->SharedFace->Face;
5531 if (face->charmap == NULL)
5532 {
5533 for (i = 0; i < (UINT)face->num_charmaps; i++)
5534 {
5535 charmap = face->charmaps[i];
5536 if (charmap->encoding != 0)
5537 {
5538 found = charmap;
5539 break;
5540 }
5541 }
5542
5543 if (!found)
5544 {
5545 DPRINT1("WARNING: Could not find desired charmap!\n");
5546 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
5547
5548 if(Safepwch)
5549 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
5550
5551 EngSetLastError(ERROR_INVALID_HANDLE);
5552 return FALSE;
5553 }
5554
5555 IntLockFreeType;
5556 FT_Set_Charmap(face, found);
5557 IntUnLockFreeType;
5558 }
5559
5560 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5561 IntLockFreeType;
5562 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
5563 FtSetCoordinateTransform(face, pmxWorldToDevice);
5564
5565 for (i = FirstChar; i < FirstChar+Count; i++)
5566 {
5567 int adv, lsb, bbx, left, right;
5568
5569 if (Safepwch)
5570 {
5571 if (fl & GCABCW_INDICES)
5572 glyph_index = Safepwch[i - FirstChar];
5573 else
5574 glyph_index = FT_Get_Char_Index(face, Safepwch[i - FirstChar]);
5575 }
5576 else
5577 {
5578 if (fl & GCABCW_INDICES)
5579 glyph_index = i;
5580 else
5581 glyph_index = FT_Get_Char_Index(face, i);
5582 }
5583 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5584
5585 left = (INT)face->glyph->metrics.horiBearingX & -64;
5586 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
5587 adv = (face->glyph->advance.x + 32) >> 6;
5588
5589 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
5590 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
5591
5592 lsb = left >> 6;
5593 bbx = (right - left) >> 6;
5594 /*
5595 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
5596 */
5597 if (!fl)
5598 {
5599 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
5600 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
5601 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
5602 }
5603 else
5604 {
5605 SafeBuff[i - FirstChar].abcA = lsb;
5606 SafeBuff[i - FirstChar].abcB = bbx;
5607 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
5608 }
5609 }
5610 IntUnLockFreeType;
5611 TEXTOBJ_UnlockText(TextObj);
5612 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
5613
5614 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
5615
5616 if(Safepwch)
5617 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
5618
5619 if (! NT_SUCCESS(Status))
5620 {
5621 SetLastNtError(Status);
5622 return FALSE;
5623 }
5624
5625 DPRINT("NtGdiGetCharABCWidths Worked!\n");
5626 return TRUE;
5627 }
5628
5629 /*
5630 * @implemented
5631 */
5632 BOOL
5633 APIENTRY
5634 NtGdiGetCharWidthW(
5635 IN HDC hDC,
5636 IN UINT FirstChar,
5637 IN UINT Count,
5638 IN OPTIONAL PWCHAR UnSafepwc,
5639 IN FLONG fl,
5640 OUT PVOID Buffer)
5641 {
5642 NTSTATUS Status = STATUS_SUCCESS;
5643 LPINT SafeBuff;
5644 PFLOAT SafeBuffF = NULL;
5645 PDC dc;
5646 PDC_ATTR pdcattr;
5647 PTEXTOBJ TextObj;
5648 PFONTGDI FontGDI;
5649 FT_Face face;
5650 FT_CharMap charmap, found = NULL;
5651 UINT i, glyph_index, BufferSize;
5652 HFONT hFont = 0;
5653 PMATRIX pmxWorldToDevice;
5654 PWCHAR Safepwc = NULL;
5655 LOGFONTW *plf;
5656
5657 if (UnSafepwc)
5658 {
5659 UINT pwcSize = Count * sizeof(WCHAR);
5660 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
5661
5662 if(!Safepwc)
5663 {
5664 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5665 return FALSE;
5666 }
5667 _SEH2_TRY
5668 {
5669 ProbeForRead(UnSafepwc, pwcSize, 1);
5670 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
5671 }
5672 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5673 {
5674 Status = _SEH2_GetExceptionCode();
5675 }
5676 _SEH2_END;
5677 }
5678
5679 if (!NT_SUCCESS(Status))
5680 {
5681 EngSetLastError(Status);
5682 return FALSE;
5683 }
5684
5685 BufferSize = Count * sizeof(INT); // Same size!
5686 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
5687 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
5688 if (SafeBuff == NULL)
5689 {
5690 if(Safepwc)
5691 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
5692
5693 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
5694 return FALSE;
5695 }
5696
5697 dc = DC_LockDc(hDC);
5698 if (dc == NULL)
5699 {
5700 if(Safepwc)
5701 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
5702
5703 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
5704 EngSetLastError(ERROR_INVALID_HANDLE);
5705 return FALSE;
5706 }
5707 pdcattr = dc->pdcattr;
5708 hFont = pdcattr->hlfntNew;
5709 TextObj = RealizeFontInit(hFont);
5710 /* Get the DC's world-to-device transformation matrix */
5711 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
5712 DC_UnlockDc(dc);
5713
5714 if (TextObj == NULL)
5715 {
5716 if(Safepwc)
5717 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
5718
5719 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
5720 EngSetLastError(ERROR_INVALID_HANDLE);
5721 return FALSE;
5722 }
5723
5724 FontGDI = ObjToGDI(TextObj->Font, FONT);
5725
5726 face = FontGDI->SharedFace->Face;
5727 if (face->charmap == NULL)
5728 {
5729 for (i = 0; i < (UINT)face->num_charmaps; i++)
5730 {
5731 charmap = face->charmaps[i];
5732 if (charmap->encoding != 0)
5733 {
5734 found = charmap;
5735 break;
5736 }
5737 }
5738
5739 if (!found)
5740 {
5741 DPRINT1("WARNING: Could not find desired charmap!\n");
5742
5743 if(Safepwc)
5744 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
5745
5746 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
5747 EngSetLastError(ERROR_INVALID_HANDLE);
5748 return FALSE;
5749 }
5750
5751 IntLockFreeType;
5752 FT_Set_Charmap(face, found);
5753 IntUnLockFreeType;
5754 }
5755
5756 plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5757 IntLockFreeType;
5758 IntRequestFontSize(dc, face, plf->lfWidth, plf->lfHeight);
5759 FtSetCoordinateTransform(face, pmxWorldToDevice);
5760
5761 for (i = FirstChar; i < FirstChar+Count; i++)
5762 {
5763 if (Safepwc)
5764 {
5765 if (fl & GCW_INDICES)
5766 glyph_index = Safepwc[i - FirstChar];
5767 else
5768 glyph_index = FT_Get_Char_Index(face, Safepwc[i - FirstChar]);
5769 }
5770 else
5771 {
5772 if (fl & GCW_INDICES)
5773 glyph_index = i;
5774 else
5775 glyph_index = FT_Get_Char_Index(face, i);
5776 }
5777 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
5778 if (!fl)
5779 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
5780 else
5781 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
5782 }
5783 IntUnLockFreeType;
5784 TEXTOBJ_UnlockText(TextObj);
5785 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
5786
5787 if(Safepwc)
5788 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
5789
5790 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
5791 return TRUE;
5792 }
5793
5794
5795 /*
5796 * @implemented
5797 */
5798 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
5799 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
5800 // NOTE: See also GreGetGlyphIndicesW.
5801 __kernel_entry
5802 W32KAPI
5803 DWORD
5804 APIENTRY
5805 NtGdiGetGlyphIndicesW(
5806 _In_ HDC hdc,
5807 _In_reads_opt_(cwc) LPCWSTR pwc,
5808 _In_ INT cwc,
5809 _Out_writes_opt_(cwc) LPWORD pgi,
5810 _In_ DWORD iMode)
5811 {
5812 PDC dc;
5813 PDC_ATTR pdcattr;
5814 PTEXTOBJ TextObj;
5815 PFONTGDI FontGDI;
5816 HFONT hFont = NULL;
5817 NTSTATUS Status = STATUS_SUCCESS;
5818 OUTLINETEXTMETRICW *potm;
5819 INT i;
5820 WCHAR DefChar = 0xffff;
5821 PWSTR Buffer = NULL;
5822 ULONG Size, pwcSize;
5823 PWSTR Safepwc = NULL;
5824 LPCWSTR UnSafepwc = pwc;
5825 LPWORD UnSafepgi = pgi;
5826
5827 /* Check for integer overflow */
5828 if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN
5829 return GDI_ERROR;
5830
5831 if (!UnSafepwc && !UnSafepgi)
5832 return cwc;
5833
5834 if (!UnSafepwc || !UnSafepgi)
5835 {
5836 DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
5837 return GDI_ERROR;
5838 }
5839
5840 // TODO: Special undocumented case!
5841 if (!pwc && !pgi && (cwc == 0))
5842 {
5843 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n");
5844 return 0;
5845 }
5846
5847 // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825
5848 if (cwc == 0)
5849 {
5850 DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n");
5851 return GDI_ERROR;
5852 }
5853
5854 dc = DC_LockDc(hdc);
5855 if (!dc)
5856 {
5857 return GDI_ERROR;
5858 }
5859 pdcattr = dc->pdcattr;
5860 hFont = pdcattr->hlfntNew;
5861 TextObj = RealizeFontInit(hFont);
5862 DC_UnlockDc(dc);
5863 if (!TextObj)
5864 {
5865 return GDI_ERROR;
5866 }
5867
5868 FontGDI = ObjToGDI(TextObj->Font, FONT);
5869 TEXTOBJ_UnlockText(TextObj);
5870
5871 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
5872 if (!Buffer)
5873 {
5874 return GDI_ERROR;
5875 }
5876
5877 if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
5878 {
5879 DefChar = 0xffff;
5880 }
5881 else
5882 {
5883 FT_Face Face = FontGDI->SharedFace->Face;
5884 if (FT_IS_SFNT(Face))
5885 {
5886 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
5887 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(Face, pOS2->usDefaultChar) : 0);
5888 }
5889 else
5890 {
5891 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
5892 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
5893 if (!potm)
5894 {
5895 cwc = GDI_ERROR;
5896 goto ErrorRet;
5897 }
5898 IntGetOutlineTextMetrics(FontGDI, Size, potm);
5899 DefChar = potm->otmTextMetrics.tmDefaultChar;
5900 ExFreePoolWithTag(potm, GDITAG_TEXT);
5901 }
5902 }
5903
5904 pwcSize = cwc * sizeof(WCHAR);
5905 Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
5906
5907 if (!Safepwc)
5908 {
5909 Status = STATUS_NO_MEMORY;
5910 goto ErrorRet;
5911 }
5912
5913 _SEH2_TRY
5914 {
5915 ProbeForRead(UnSafepwc, pwcSize, 1);
5916 RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
5917 }
5918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5919 {
5920 Status = _SEH2_GetExceptionCode();
5921 }
5922 _SEH2_END;
5923
5924 if (!NT_SUCCESS(Status)) goto ErrorRet;
5925
5926 IntLockFreeType;
5927
5928 for (i = 0; i < cwc; i++)
5929 {
5930 Buffer[i] = FT_Get_Char_Index(FontGDI->SharedFace->Face, Safepwc[i]);
5931 if (Buffer[i] == 0)
5932 {
5933 Buffer[i] = DefChar;
5934 }
5935 }
5936
5937 IntUnLockFreeType;
5938
5939 _SEH2_TRY
5940 {
5941 ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
5942 RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
5943 }
5944 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5945 {
5946 Status = _SEH2_GetExceptionCode();
5947 }
5948 _SEH2_END;
5949
5950 ErrorRet:
5951 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
5952 if (Safepwc != NULL)
5953 {
5954 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
5955 }
5956 if (NT_SUCCESS(Status)) return cwc;
5957 return GDI_ERROR;
5958 }
5959
5960 /* EOF */