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