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