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