bee889d4339d93154af86ae380158a2bcf6b9e67
[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 FT_Done_Glyph(GlyphCopy);
1353 DPRINT1("Failure rendering glyph.\n");
1354 return NULL;
1355 };
1356
1357 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
1358 if (!NewEntry)
1359 {
1360 DPRINT1("Alloc failure caching glyph.\n");
1361 FT_Done_Glyph(GlyphCopy);
1362 return NULL;
1363 }
1364
1365 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
1366 FT_Bitmap_New(&AlignedBitmap);
1367 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
1368 {
1369 DPRINT1("Conversion failed\n");
1370 ExFreePoolWithTag(NewEntry, TAG_FONT);
1371 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
1372 return NULL;
1373 }
1374
1375 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
1376 BitmapGlyph->bitmap = AlignedBitmap;
1377
1378 NewEntry->GlyphIndex = GlyphIndex;
1379 NewEntry->Face = Face;
1380 NewEntry->BitmapGlyph = BitmapGlyph;
1381 NewEntry->Height = Height;
1382
1383 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
1384 if (FontCacheNumEntries++ > MAX_FONT_CACHE)
1385 {
1386 NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
1387 FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph);
1388 RemoveTailList(&FontCacheListHead);
1389 ExFreePool(NewEntry);
1390 FontCacheNumEntries--;
1391 }
1392
1393 return BitmapGlyph;
1394 }
1395
1396
1397 static
1398 void
1399 FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1400 {
1401 pt->x.value = vec->x >> 6;
1402 pt->x.fract = (vec->x & 0x3f) << 10;
1403 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1404 pt->y.value = vec->y >> 6;
1405 pt->y.fract = (vec->y & 0x3f) << 10;
1406 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1407 return;
1408 }
1409
1410 /*
1411 This function builds an FT_Fixed from a float. It puts the integer part
1412 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
1413 It fails if the integer part of the float number is greater than SHORT_MAX.
1414 */
1415 static __inline FT_Fixed FT_FixedFromFloat(float f)
1416 {
1417 short value = f;
1418 unsigned short fract = (f - value) * 0xFFFF;
1419 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
1420 }
1421
1422 /*
1423 This function builds an FT_Fixed from a FIXED. It simply put f.value
1424 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
1425 */
1426 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
1427 {
1428 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
1429 }
1430
1431 /*
1432 * Based on WineEngGetGlyphOutline
1433 *
1434 */
1435 ULONG
1436 FASTCALL
1437 ftGdiGetGlyphOutline(
1438 PDC dc,
1439 WCHAR wch,
1440 UINT iFormat,
1441 LPGLYPHMETRICS pgm,
1442 ULONG cjBuf,
1443 PVOID pvBuf,
1444 LPMAT2 pmat2,
1445 BOOL bIgnoreRotation)
1446 {
1447 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
1448 PDC_ATTR pdcattr;
1449 PTEXTOBJ TextObj;
1450 PFONTGDI FontGDI;
1451 HFONT hFont = 0;
1452 GLYPHMETRICS gm;
1453 ULONG Size;
1454 FT_Face ft_face;
1455 FT_UInt glyph_index;
1456 DWORD width, height, pitch, needed = 0;
1457 FT_Bitmap ft_bitmap;
1458 FT_Error error;
1459 INT left, right, top = 0, bottom = 0;
1460 FT_Angle angle = 0;
1461 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
1462 FLOAT eM11, widthRatio = 1.0;
1463 FT_Matrix transMat = identityMat;
1464 BOOL needsTransform = FALSE;
1465 INT orientation;
1466 LONG aveWidth;
1467 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
1468 OUTLINETEXTMETRICW *potm;
1469 int n = 0;
1470 FT_CharMap found = 0, charmap;
1471 XFORM xForm;
1472
1473 DPRINT("%d, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
1474 cjBuf, pvBuf, pmat2);
1475
1476 pdcattr = dc->pdcattr;
1477
1478 MatrixS2XForm(&xForm, &dc->dclevel.mxWorldToDevice);
1479 eM11 = xForm.eM11;
1480
1481 hFont = pdcattr->hlfntNew;
1482 TextObj = RealizeFontInit(hFont);
1483
1484 if (!TextObj)
1485 {
1486 EngSetLastError(ERROR_INVALID_HANDLE);
1487 return GDI_ERROR;
1488 }
1489 FontGDI = ObjToGDI(TextObj->Font, FONT);
1490 ft_face = FontGDI->face;
1491
1492 aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth: 0;
1493 orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation: 0;
1494
1495 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
1496 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
1497 if (!potm)
1498 {
1499 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1500 TEXTOBJ_UnlockText(TextObj);
1501 return GDI_ERROR;
1502 }
1503 IntGetOutlineTextMetrics(FontGDI, Size, potm);
1504
1505 IntLockFreeType;
1506
1507 /* During testing, I never saw this used. It is here just in case. */
1508 if (ft_face->charmap == NULL)
1509 {
1510 DPRINT("WARNING: No charmap selected!\n");
1511 DPRINT("This font face has %d charmaps\n", ft_face->num_charmaps);
1512
1513 for (n = 0; n < ft_face->num_charmaps; n++)
1514 {
1515 charmap = ft_face->charmaps[n];
1516 DPRINT("Found charmap encoding: %u\n", charmap->encoding);
1517 if (charmap->encoding != 0)
1518 {
1519 found = charmap;
1520 break;
1521 }
1522 }
1523 if (!found)
1524 {
1525 DPRINT1("WARNING: Could not find desired charmap!\n");
1526 }
1527 error = FT_Set_Charmap(ft_face, found);
1528 if (error)
1529 {
1530 DPRINT1("WARNING: Could not set the charmap!\n");
1531 }
1532 }
1533
1534 // FT_Set_Pixel_Sizes(ft_face,
1535 // TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
1536 /* FIXME: Should set character height if neg */
1537 // (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
1538 // dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
1539
1540 TEXTOBJ_UnlockText(TextObj);
1541
1542 if (iFormat & GGO_GLYPH_INDEX)
1543 {
1544 glyph_index = wch;
1545 iFormat &= ~GGO_GLYPH_INDEX;
1546 }
1547 else glyph_index = FT_Get_Char_Index(ft_face, wch);
1548
1549 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
1550 load_flags |= FT_LOAD_NO_BITMAP;
1551
1552 if (iFormat & GGO_UNHINTED)
1553 {
1554 load_flags |= FT_LOAD_NO_HINTING;
1555 iFormat &= ~GGO_UNHINTED;
1556 }
1557
1558 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
1559 if (error)
1560 {
1561 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1562 IntUnLockFreeType;
1563 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
1564 return GDI_ERROR;
1565 }
1566 IntUnLockFreeType;
1567
1568 if (aveWidth && potm)
1569 {
1570 widthRatio = (FLOAT)aveWidth * eM11 /
1571 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
1572 }
1573
1574 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
1575 right = (INT)((ft_face->glyph->metrics.horiBearingX +
1576 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
1577
1578 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
1579 lsb = left >> 6;
1580 bbx = (right - left) >> 6;
1581
1582 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
1583
1584 IntLockFreeType;
1585
1586 /* Scaling transform */
1587 if (aveWidth)
1588 {
1589 FT_Matrix scaleMat;
1590 DPRINT("Scaling Trans!\n");
1591 scaleMat.xx = FT_FixedFromFloat(widthRatio);
1592 scaleMat.xy = 0;
1593 scaleMat.yx = 0;
1594 scaleMat.yy = (1 << 16);
1595 FT_Matrix_Multiply(&scaleMat, &transMat);
1596 needsTransform = TRUE;
1597 }
1598
1599 /* Slant transform */
1600 if (potm->otmTextMetrics.tmItalic)
1601 {
1602 FT_Matrix slantMat;
1603 DPRINT("Slant Trans!\n");
1604 slantMat.xx = (1 << 16);
1605 slantMat.xy = ((1 << 16) >> 2);
1606 slantMat.yx = 0;
1607 slantMat.yy = (1 << 16);
1608 FT_Matrix_Multiply(&slantMat, &transMat);
1609 needsTransform = TRUE;
1610 }
1611
1612 /* Rotation transform */
1613 if (orientation)
1614 {
1615 FT_Matrix rotationMat;
1616 FT_Vector vecAngle;
1617 DPRINT("Rotation Trans!\n");
1618 angle = FT_FixedFromFloat((float)orientation / 10.0);
1619 FT_Vector_Unit(&vecAngle, angle);
1620 rotationMat.xx = vecAngle.x;
1621 rotationMat.xy = -vecAngle.y;
1622 rotationMat.yx = -rotationMat.xy;
1623 rotationMat.yy = rotationMat.xx;
1624 FT_Matrix_Multiply(&rotationMat, &transMat);
1625 needsTransform = TRUE;
1626 }
1627
1628 /* Extra transformation specified by caller */
1629 if (pmat2)
1630 {
1631 FT_Matrix extraMat;
1632 DPRINT("MAT2 Matrix Trans!\n");
1633 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
1634 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
1635 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
1636 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
1637 FT_Matrix_Multiply(&extraMat, &transMat);
1638 needsTransform = TRUE;
1639 }
1640
1641 if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
1642
1643 if (!needsTransform)
1644 {
1645 DPRINT("No Need to be Transformed!\n");
1646 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1647 bottom = (ft_face->glyph->metrics.horiBearingY -
1648 ft_face->glyph->metrics.height) & -64;
1649 gm.gmCellIncX = adv;
1650 gm.gmCellIncY = 0;
1651 }
1652 else
1653 {
1654 INT xc, yc;
1655 FT_Vector vec;
1656 for (xc = 0; xc < 2; xc++)
1657 {
1658 for (yc = 0; yc < 2; yc++)
1659 {
1660 vec.x = (ft_face->glyph->metrics.horiBearingX +
1661 xc * ft_face->glyph->metrics.width);
1662 vec.y = ft_face->glyph->metrics.horiBearingY -
1663 yc * ft_face->glyph->metrics.height;
1664 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
1665 FT_Vector_Transform(&vec, &transMat);
1666 if (xc == 0 && yc == 0)
1667 {
1668 left = right = vec.x;
1669 top = bottom = vec.y;
1670 }
1671 else
1672 {
1673 if (vec.x < left) left = vec.x;
1674 else if (vec.x > right) right = vec.x;
1675 if (vec.y < bottom) bottom = vec.y;
1676 else if (vec.y > top) top = vec.y;
1677 }
1678 }
1679 }
1680 left = left & -64;
1681 right = (right + 63) & -64;
1682 bottom = bottom & -64;
1683 top = (top + 63) & -64;
1684
1685 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1686 vec.x = ft_face->glyph->metrics.horiAdvance;
1687 vec.y = 0;
1688 FT_Vector_Transform(&vec, &transMat);
1689 gm.gmCellIncX = (vec.x+63) >> 6;
1690 gm.gmCellIncY = -((vec.y+63) >> 6);
1691 }
1692 gm.gmBlackBoxX = (right - left) >> 6;
1693 gm.gmBlackBoxY = (top - bottom) >> 6;
1694 gm.gmptGlyphOrigin.x = left >> 6;
1695 gm.gmptGlyphOrigin.y = top >> 6;
1696
1697 DPRINT("CX %d CY %d BBX %d BBY %d GOX %d GOY %d\n",
1698 gm.gmCellIncX, gm.gmCellIncY,
1699 gm.gmBlackBoxX, gm.gmBlackBoxY,
1700 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1701
1702 IntUnLockFreeType;
1703
1704 if (pgm) RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
1705
1706 if (iFormat == GGO_METRICS)
1707 {
1708 DPRINT("GGO_METRICS Exit!\n");
1709 return 1; /* FIXME */
1710 }
1711
1712 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
1713 {
1714 DPRINT1("Loaded a bitmap\n");
1715 return GDI_ERROR;
1716 }
1717
1718 switch (iFormat)
1719 {
1720 case GGO_BITMAP:
1721 width = gm.gmBlackBoxX;
1722 height = gm.gmBlackBoxY;
1723 pitch = ((width + 31) >> 5) << 2;
1724 needed = pitch * height;
1725
1726 if (!pvBuf || !cjBuf) break;
1727
1728 switch (ft_face->glyph->format)
1729 {
1730 case ft_glyph_format_bitmap:
1731 {
1732 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
1733 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1734 INT h = ft_face->glyph->bitmap.rows;
1735 while (h--)
1736 {
1737 RtlCopyMemory(dst, src, w);
1738 src += ft_face->glyph->bitmap.pitch;
1739 dst += pitch;
1740 }
1741 break;
1742 }
1743
1744 case ft_glyph_format_outline:
1745 ft_bitmap.width = width;
1746 ft_bitmap.rows = height;
1747 ft_bitmap.pitch = pitch;
1748 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1749 ft_bitmap.buffer = pvBuf;
1750
1751 IntLockFreeType;
1752 if (needsTransform)
1753 {
1754 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1755 }
1756 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1757 /* Note: FreeType will only set 'black' bits for us. */
1758 RtlZeroMemory(pvBuf, needed);
1759 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1760 IntUnLockFreeType;
1761 break;
1762
1763 default:
1764 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
1765 return GDI_ERROR;
1766 }
1767 break;
1768
1769 case GGO_GRAY2_BITMAP:
1770 case GGO_GRAY4_BITMAP:
1771 case GGO_GRAY8_BITMAP:
1772 {
1773 unsigned int mult, row, col;
1774 BYTE *start, *ptr;
1775
1776 width = gm.gmBlackBoxX;
1777 height = gm.gmBlackBoxY;
1778 pitch = (width + 3) / 4 * 4;
1779 needed = pitch * height;
1780
1781 if (!pvBuf || !cjBuf) break;
1782
1783 switch (ft_face->glyph->format)
1784 {
1785 case ft_glyph_format_bitmap:
1786 {
1787 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
1788 INT h = ft_face->glyph->bitmap.rows;
1789 INT x;
1790 while (h--)
1791 {
1792 for (x = 0; x < pitch; x++)
1793 {
1794 if (x < ft_face->glyph->bitmap.width)
1795 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
1796 else
1797 dst[x] = 0;
1798 }
1799 src += ft_face->glyph->bitmap.pitch;
1800 dst += pitch;
1801 }
1802 return needed;
1803 }
1804 case ft_glyph_format_outline:
1805 {
1806 ft_bitmap.width = width;
1807 ft_bitmap.rows = height;
1808 ft_bitmap.pitch = pitch;
1809 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1810 ft_bitmap.buffer = pvBuf;
1811
1812 IntLockFreeType;
1813 if (needsTransform)
1814 {
1815 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1816 }
1817 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1818 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
1819 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1820 IntUnLockFreeType;
1821
1822 if (iFormat == GGO_GRAY2_BITMAP)
1823 mult = 4;
1824 else if (iFormat == GGO_GRAY4_BITMAP)
1825 mult = 16;
1826 else if (iFormat == GGO_GRAY8_BITMAP)
1827 mult = 64;
1828 else
1829 {
1830 return GDI_ERROR;
1831 }
1832 }
1833 default:
1834 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
1835 return GDI_ERROR;
1836 }
1837 start = pvBuf;
1838 for (row = 0; row < height; row++)
1839 {
1840 ptr = start;
1841 for (col = 0; col < width; col++, ptr++)
1842 {
1843 *ptr = (((int)*ptr) * mult + 128) / 256;
1844 }
1845 start += pitch;
1846 }
1847 break;
1848 }
1849
1850 case GGO_NATIVE:
1851 {
1852 int contour, point = 0, first_pt;
1853 FT_Outline *outline = &ft_face->glyph->outline;
1854 TTPOLYGONHEADER *pph;
1855 TTPOLYCURVE *ppc;
1856 DWORD pph_start, cpfx, type;
1857
1858 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
1859
1860 IntLockFreeType;
1861 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
1862
1863 for (contour = 0; contour < outline->n_contours; contour++)
1864 {
1865 pph_start = needed;
1866 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
1867 first_pt = point;
1868 if (pvBuf)
1869 {
1870 pph->dwType = TT_POLYGON_TYPE;
1871 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1872 }
1873 needed += sizeof(*pph);
1874 point++;
1875 while (point <= outline->contours[contour])
1876 {
1877 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
1878 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1879 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1880 cpfx = 0;
1881 do
1882 {
1883 if (pvBuf)
1884 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1885 cpfx++;
1886 point++;
1887 }
1888 while (point <= outline->contours[contour] &&
1889 (outline->tags[point] & FT_Curve_Tag_On) ==
1890 (outline->tags[point-1] & FT_Curve_Tag_On));
1891
1892 /* At the end of a contour Windows adds the start point, but
1893 only for Beziers */
1894 if (point > outline->contours[contour] &&
1895 !(outline->tags[point-1] & FT_Curve_Tag_On))
1896 {
1897 if (pvBuf)
1898 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1899 cpfx++;
1900 }
1901 else if (point <= outline->contours[contour] &&
1902 outline->tags[point] & FT_Curve_Tag_On)
1903 {
1904 /* Add closing pt for bezier */
1905 if (pvBuf)
1906 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1907 cpfx++;
1908 point++;
1909 }
1910 if (pvBuf)
1911 {
1912 ppc->wType = type;
1913 ppc->cpfx = cpfx;
1914 }
1915 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1916 }
1917 if (pvBuf) pph->cb = needed - pph_start;
1918 }
1919 IntUnLockFreeType;
1920 break;
1921 }
1922 case GGO_BEZIER:
1923 {
1924 /* Convert the quadratic Beziers to cubic Beziers.
1925 The parametric eqn for a cubic Bezier is, from PLRM:
1926 r(t) = at^3 + bt^2 + ct + r0
1927 with the control points:
1928 r1 = r0 + c/3
1929 r2 = r1 + (c + b)/3
1930 r3 = r0 + c + b + a
1931
1932 A quadratic Beizer has the form:
1933 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1934
1935 So equating powers of t leads to:
1936 r1 = 2/3 p1 + 1/3 p0
1937 r2 = 2/3 p1 + 1/3 p2
1938 and of course r0 = p0, r3 = p2
1939 */
1940
1941 int contour, point = 0, first_pt;
1942 FT_Outline *outline = &ft_face->glyph->outline;
1943 TTPOLYGONHEADER *pph;
1944 TTPOLYCURVE *ppc;
1945 DWORD pph_start, cpfx, type;
1946 FT_Vector cubic_control[4];
1947 if (cjBuf == 0) pvBuf = NULL;
1948
1949 if (needsTransform && pvBuf)
1950 {
1951 IntLockFreeType;
1952 FT_Outline_Transform(outline, &transMat);
1953 IntUnLockFreeType;
1954 }
1955
1956 for (contour = 0; contour < outline->n_contours; contour++)
1957 {
1958 pph_start = needed;
1959 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
1960 first_pt = point;
1961 if (pvBuf)
1962 {
1963 pph->dwType = TT_POLYGON_TYPE;
1964 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1965 }
1966 needed += sizeof(*pph);
1967 point++;
1968 while (point <= outline->contours[contour])
1969 {
1970 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
1971 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1972 TT_PRIM_LINE : TT_PRIM_CSPLINE;
1973 cpfx = 0;
1974 do
1975 {
1976 if (type == TT_PRIM_LINE)
1977 {
1978 if (pvBuf)
1979 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1980 cpfx++;
1981 point++;
1982 }
1983 else
1984 {
1985 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
1986 so cpfx = 3n */
1987
1988 /* FIXME: Possible optimization in endpoint calculation
1989 if there are two consecutive curves */
1990 cubic_control[0] = outline->points[point-1];
1991 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
1992 {
1993 cubic_control[0].x += outline->points[point].x + 1;
1994 cubic_control[0].y += outline->points[point].y + 1;
1995 cubic_control[0].x >>= 1;
1996 cubic_control[0].y >>= 1;
1997 }
1998 if (point+1 > outline->contours[contour])
1999 cubic_control[3] = outline->points[first_pt];
2000 else
2001 {
2002 cubic_control[3] = outline->points[point+1];
2003 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2004 {
2005 cubic_control[3].x += outline->points[point].x + 1;
2006 cubic_control[3].y += outline->points[point].y + 1;
2007 cubic_control[3].x >>= 1;
2008 cubic_control[3].y >>= 1;
2009 }
2010 }
2011 /* r1 = 1/3 p0 + 2/3 p1
2012 r2 = 1/3 p2 + 2/3 p1 */
2013 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2014 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2015 cubic_control[2] = cubic_control[1];
2016 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2017 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2018 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2019 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2020 if (pvBuf)
2021 {
2022 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2023 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2024 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2025 }
2026 cpfx += 3;
2027 point++;
2028 }
2029 }
2030 while (point <= outline->contours[contour] &&
2031 (outline->tags[point] & FT_Curve_Tag_On) ==
2032 (outline->tags[point-1] & FT_Curve_Tag_On));
2033 /* At the end of a contour Windows adds the start point,
2034 but only for Beziers and we've already done that. */
2035 if (point <= outline->contours[contour] &&
2036 outline->tags[point] & FT_Curve_Tag_On)
2037 {
2038 /* This is the closing pt of a bezier, but we've already
2039 added it, so just inc point and carry on */
2040 point++;
2041 }
2042 if (pvBuf)
2043 {
2044 ppc->wType = type;
2045 ppc->cpfx = cpfx;
2046 }
2047 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2048 }
2049 if (pvBuf) pph->cb = needed - pph_start;
2050 }
2051 break;
2052 }
2053
2054 default:
2055 DPRINT1("Unsupported format %d\n", iFormat);
2056 return GDI_ERROR;
2057 }
2058
2059 DPRINT("ftGdiGetGlyphOutline END and needed %d\n", needed);
2060 return needed;
2061 }
2062
2063 BOOL
2064 FASTCALL
2065 TextIntGetTextExtentPoint(PDC dc,
2066 PTEXTOBJ TextObj,
2067 LPCWSTR String,
2068 INT Count,
2069 ULONG MaxExtent,
2070 LPINT Fit,
2071 LPINT Dx,
2072 LPSIZE Size,
2073 FLONG fl)
2074 {
2075 PFONTGDI FontGDI;
2076 FT_Face face;
2077 FT_GlyphSlot glyph;
2078 FT_BitmapGlyph realglyph;
2079 INT error, n, glyph_index, i, previous;
2080 ULONGLONG TotalWidth = 0;
2081 FT_CharMap charmap, found = NULL;
2082 BOOL use_kerning;
2083 FT_Render_Mode RenderMode;
2084 BOOLEAN Render;
2085
2086 FontGDI = ObjToGDI(TextObj->Font, FONT);
2087
2088 face = FontGDI->face;
2089 if (NULL != Fit)
2090 {
2091 *Fit = 0;
2092 }
2093
2094 IntLockFreeType;
2095 if (face->charmap == NULL)
2096 {
2097 DPRINT("WARNING: No charmap selected!\n");
2098 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2099
2100 for (n = 0; n < face->num_charmaps; n++)
2101 {
2102 charmap = face->charmaps[n];
2103 DPRINT("Found charmap encoding: %u\n", charmap->encoding);
2104 if (charmap->encoding != 0)
2105 {
2106 found = charmap;
2107 break;
2108 }
2109 }
2110
2111 if (! found)
2112 {
2113 DPRINT1("WARNING: Could not find desired charmap!\n");
2114 }
2115
2116 error = FT_Set_Charmap(face, found);
2117 if (error)
2118 {
2119 DPRINT1("WARNING: Could not set the charmap!\n");
2120 }
2121 }
2122
2123 Render = IntIsFontRenderingEnabled();
2124 if (Render)
2125 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
2126 else
2127 RenderMode = FT_RENDER_MODE_MONO;
2128
2129 error = FT_Set_Pixel_Sizes(face,
2130 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
2131 /* FIXME: Should set character height if neg */
2132 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
2133 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
2134 if (error)
2135 {
2136 DPRINT1("Error in setting pixel sizes: %u\n", error);
2137 }
2138
2139 use_kerning = FT_HAS_KERNING(face);
2140 previous = 0;
2141
2142 for (i = 0; i < Count; i++)
2143 {
2144 if (fl & GTEF_INDICES)
2145 glyph_index = *String;
2146 else
2147 glyph_index = FT_Get_Char_Index(face, *String);
2148
2149 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
2150 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
2151 {
2152 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2153 if (error)
2154 {
2155 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
2156 break;
2157 }
2158
2159 glyph = face->glyph;
2160 realglyph = ftGdiGlyphCacheSet(face, glyph_index,
2161 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
2162 if (!realglyph)
2163 {
2164 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
2165 break;
2166 }
2167 }
2168
2169 /* Retrieve kerning distance */
2170 if (use_kerning && previous && glyph_index)
2171 {
2172 FT_Vector delta;
2173 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
2174 TotalWidth += delta.x;
2175 }
2176
2177 TotalWidth += realglyph->root.advance.x >> 10;
2178
2179 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
2180 {
2181 *Fit = i + 1;
2182 }
2183 if (NULL != Dx)
2184 {
2185 Dx[i] = (TotalWidth + 32) >> 6;
2186 }
2187
2188 previous = glyph_index;
2189 String++;
2190 }
2191 IntUnLockFreeType;
2192
2193 Size->cx = (TotalWidth + 32) >> 6;
2194 Size->cy = (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
2195 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
2196 Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
2197
2198 return TRUE;
2199 }
2200
2201
2202 INT
2203 FASTCALL
2204 ftGdiGetTextCharsetInfo(
2205 PDC Dc,
2206 LPFONTSIGNATURE lpSig,
2207 DWORD dwFlags)
2208 {
2209 PDC_ATTR pdcattr;
2210 UINT Ret = DEFAULT_CHARSET, i;
2211 HFONT hFont;
2212 PTEXTOBJ TextObj;
2213 PFONTGDI FontGdi;
2214 FONTSIGNATURE fs;
2215 TT_OS2 *pOS2;
2216 FT_Face Face;
2217 CHARSETINFO csi;
2218 DWORD cp, fs0;
2219 USHORT usACP, usOEM;
2220
2221 pdcattr = Dc->pdcattr;
2222 hFont = pdcattr->hlfntNew;
2223 TextObj = RealizeFontInit(hFont);
2224
2225 if (!TextObj)
2226 {
2227 EngSetLastError(ERROR_INVALID_HANDLE);
2228 return Ret;
2229 }
2230 FontGdi = ObjToGDI(TextObj->Font, FONT);
2231 Face = FontGdi->face;
2232 TEXTOBJ_UnlockText(TextObj);
2233
2234 IntLockFreeType;
2235 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2236 IntUnLockFreeType;
2237 memset(&fs, 0, sizeof(FONTSIGNATURE));
2238 if (NULL != pOS2)
2239 {
2240 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2241 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2242 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2243 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2244 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2245 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2246 if (pOS2->version == 0)
2247 {
2248 FT_UInt dummy;
2249
2250 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
2251 fs.fsCsb[0] |= FS_LATIN1;
2252 else
2253 fs.fsCsb[0] |= FS_SYMBOL;
2254 }
2255 }
2256 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
2257 if (fs.fsCsb[0] == 0)
2258 { /* Let's see if we can find any interesting cmaps */
2259 for (i = 0; i < Face->num_charmaps; i++)
2260 {
2261 switch (Face->charmaps[i]->encoding)
2262 {
2263 case FT_ENCODING_UNICODE:
2264 case FT_ENCODING_APPLE_ROMAN:
2265 fs.fsCsb[0] |= FS_LATIN1;
2266 break;
2267 case FT_ENCODING_MS_SYMBOL:
2268 fs.fsCsb[0] |= FS_SYMBOL;
2269 break;
2270 default:
2271 break;
2272 }
2273 }
2274 }
2275 if (lpSig)
2276 {
2277 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
2278 }
2279
2280 RtlGetDefaultCodePage(&usACP, &usOEM);
2281 cp = usACP;
2282
2283 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
2284 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
2285 {
2286 DPRINT("Hit 1\n");
2287 Ret = csi.ciCharset;
2288 goto Exit;
2289 }
2290
2291 for (i = 0; i < MAXTCIINDEX; i++)
2292 {
2293 fs0 = 1L << i;
2294 if (fs.fsCsb[0] & fs0)
2295 {
2296 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
2297 {
2298 // *cp = csi.ciACP;
2299 DPRINT("Hit 2\n");
2300 Ret = csi.ciCharset;
2301 goto Exit;
2302 }
2303 else
2304 DPRINT1("TCI failing on %x\n", fs0);
2305 }
2306 }
2307 Exit:
2308 DPRINT("CharSet %d CodePage %d\n",csi.ciCharset, csi.ciACP);
2309 return (MAKELONG(csi.ciACP, csi.ciCharset));
2310 }
2311
2312
2313 DWORD
2314 FASTCALL
2315 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
2316 {
2317 DWORD size = 0;
2318 DWORD num_ranges = 0;
2319 FT_Face face = Font->face;
2320
2321 if (face->charmap->encoding == FT_ENCODING_UNICODE)
2322 {
2323 FT_UInt glyph_code = 0;
2324 FT_ULong char_code, char_code_prev;
2325
2326 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
2327
2328 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
2329 face->num_glyphs, glyph_code, char_code);
2330
2331 if (!glyph_code) return 0;
2332
2333 if (glyphset)
2334 {
2335 glyphset->ranges[0].wcLow = (USHORT)char_code;
2336 glyphset->ranges[0].cGlyphs = 0;
2337 glyphset->cGlyphsSupported = 0;
2338 }
2339
2340 num_ranges = 1;
2341 while (glyph_code)
2342 {
2343 if (char_code < char_code_prev)
2344 {
2345 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
2346 return 0;
2347 }
2348 if (char_code - char_code_prev > 1)
2349 {
2350 num_ranges++;
2351 if (glyphset)
2352 {
2353 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
2354 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
2355 glyphset->cGlyphsSupported++;
2356 }
2357 }
2358 else if (glyphset)
2359 {
2360 glyphset->ranges[num_ranges - 1].cGlyphs++;
2361 glyphset->cGlyphsSupported++;
2362 }
2363 char_code_prev = char_code;
2364 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
2365 }
2366 }
2367 else
2368 DPRINT1("Encoding %u not supported\n", face->charmap->encoding);
2369
2370 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
2371 if (glyphset)
2372 {
2373 glyphset->cbThis = size;
2374 glyphset->cRanges = num_ranges;
2375 }
2376 return size;
2377 }
2378
2379
2380 BOOL
2381 FASTCALL
2382 ftGdiGetTextMetricsW(
2383 HDC hDC,
2384 PTMW_INTERNAL ptmwi)
2385 {
2386 PDC dc;
2387 PDC_ATTR pdcattr;
2388 PTEXTOBJ TextObj;
2389 PFONTGDI FontGDI;
2390 FT_Face Face;
2391 TT_OS2 *pOS2;
2392 TT_HoriHeader *pHori;
2393 FT_WinFNT_HeaderRec Win;
2394 ULONG Error;
2395 NTSTATUS Status = STATUS_SUCCESS;
2396
2397 if (!ptmwi)
2398 {
2399 EngSetLastError(STATUS_INVALID_PARAMETER);
2400 return FALSE;
2401 }
2402
2403 if (!(dc = DC_LockDc(hDC)))
2404 {
2405 EngSetLastError(ERROR_INVALID_HANDLE);
2406 return FALSE;
2407 }
2408 pdcattr = dc->pdcattr;
2409 TextObj = RealizeFontInit(pdcattr->hlfntNew);
2410 if (NULL != TextObj)
2411 {
2412 FontGDI = ObjToGDI(TextObj->Font, FONT);
2413
2414 Face = FontGDI->face;
2415 IntLockFreeType;
2416 Error = FT_Set_Pixel_Sizes(Face,
2417 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
2418 /* FIXME: Should set character height if neg */
2419 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
2420 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
2421 IntUnLockFreeType;
2422 if (0 != Error)
2423 {
2424 DPRINT1("Error in setting pixel sizes: %u\n", Error);
2425 Status = STATUS_UNSUCCESSFUL;
2426 }
2427 else
2428 {
2429 Status = STATUS_SUCCESS;
2430
2431 IntLockFreeType;
2432 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
2433 if (NULL == pOS2)
2434 {
2435 DPRINT1("Can't find OS/2 table - not TT font?\n");
2436 Status = STATUS_INTERNAL_ERROR;
2437 }
2438
2439 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
2440 if (NULL == pHori)
2441 {
2442 DPRINT1("Can't find HHEA table - not TT font?\n");
2443 Status = STATUS_INTERNAL_ERROR;
2444 }
2445
2446 Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
2447
2448 IntUnLockFreeType;
2449
2450 if (NT_SUCCESS(Status))
2451 {
2452 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
2453
2454 /* FIXME: Fill Diff member */
2455 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
2456 }
2457 }
2458 TEXTOBJ_UnlockText(TextObj);
2459 }
2460 else
2461 {
2462 Status = STATUS_INVALID_HANDLE;
2463 }
2464 DC_UnlockDc(dc);
2465
2466 if (!NT_SUCCESS(Status))
2467 {
2468 SetLastNtError(Status);
2469 return FALSE;
2470 }
2471 return TRUE;
2472 }
2473
2474
2475 DWORD
2476 FASTCALL
2477 ftGdiGetFontData(
2478 PFONTGDI FontGdi,
2479 DWORD Table,
2480 DWORD Offset,
2481 PVOID Buffer,
2482 DWORD Size)
2483 {
2484 DWORD Result = GDI_ERROR;
2485
2486 IntLockFreeType;
2487
2488 if (FT_IS_SFNT(FontGdi->face))
2489 {
2490 if (Table)
2491 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
2492 (Table << 8 & 0xFF0000);
2493
2494 if (!Buffer) Size = 0;
2495
2496 if (Buffer && Size)
2497 {
2498 FT_Error Error;
2499 FT_ULong Needed = 0;
2500
2501 Error = FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, NULL, &Needed);
2502
2503 if ( !Error && Needed < Size) Size = Needed;
2504 }
2505 if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
2506 Result = Size;
2507 }
2508
2509 IntUnLockFreeType;
2510
2511 return Result;
2512 }
2513
2514 static UINT FASTCALL
2515 GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
2516 {
2517 ANSI_STRING EntryFaceNameA;
2518 UNICODE_STRING EntryFaceNameW;
2519 unsigned Size;
2520 OUTLINETEXTMETRICW *Otm;
2521 LONG WeightDiff;
2522 NTSTATUS Status;
2523 UINT Score = 1;
2524
2525 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
2526 Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2527 if (NT_SUCCESS(Status))
2528 {
2529 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2530 {
2531 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2532 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2533 }
2534 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
2535 {
2536 Score += 49;
2537 }
2538 RtlFreeUnicodeString(&EntryFaceNameW);
2539 }
2540
2541 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2542 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2543 if (NULL == Otm)
2544 {
2545 return Score;
2546 }
2547 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2548
2549 if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
2550 (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
2551 {
2552 Score += 25;
2553 }
2554 if (LogFont->lfWeight != FW_DONTCARE)
2555 {
2556 if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
2557 {
2558 WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
2559 }
2560 else
2561 {
2562 WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
2563 }
2564 Score += (1000 - WeightDiff) / (1000 / 25);
2565 }
2566 else
2567 {
2568 Score += 25;
2569 }
2570
2571 ExFreePool(Otm);
2572
2573 return Score;
2574 }
2575
2576 static __inline VOID
2577 FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
2578 PUNICODE_STRING FaceName, PLIST_ENTRY Head)
2579 {
2580 PLIST_ENTRY Entry;
2581 PFONT_ENTRY CurrentEntry;
2582 FONTGDI *FontGDI;
2583 UINT Score;
2584 ASSERT(FontObj && MatchScore && LogFont && FaceName && Head);
2585 Entry = Head->Flink;
2586 while (Entry != Head)
2587 {
2588 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2589
2590 FontGDI = CurrentEntry->Font;
2591 ASSERT(FontGDI);
2592
2593 Score = GetFontScore(LogFont, FaceName, FontGDI);
2594 if (*MatchScore == 0 || *MatchScore < Score)
2595 {
2596 *FontObj = GDIToObj(FontGDI, FONT);
2597 *MatchScore = Score;
2598 }
2599 Entry = Entry->Flink;
2600 }
2601 }
2602
2603 static __inline BOOLEAN
2604 SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
2605 LPCWSTR Key)
2606 {
2607 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2608 NTSTATUS Status;
2609 UNICODE_STRING Value;
2610
2611 RtlInitUnicodeString(&Value, NULL);
2612
2613 QueryTable[0].QueryRoutine = NULL;
2614 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
2615 RTL_QUERY_REGISTRY_REQUIRED;
2616 QueryTable[0].Name = FaceName->Buffer;
2617 QueryTable[0].EntryContext = &Value;
2618 QueryTable[0].DefaultType = REG_NONE;
2619 QueryTable[0].DefaultData = NULL;
2620 QueryTable[0].DefaultLength = 0;
2621
2622 QueryTable[1].QueryRoutine = NULL;
2623 QueryTable[1].Name = NULL;
2624
2625 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2626 Key,
2627 QueryTable,
2628 NULL,
2629 NULL);
2630 if (NT_SUCCESS(Status))
2631 {
2632 RtlFreeUnicodeString(FaceName);
2633 *FaceName = Value;
2634 }
2635
2636 return NT_SUCCESS(Status);
2637 }
2638
2639 static __inline void
2640 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
2641 {
2642 if (10 < Level) /* Enough is enough */
2643 {
2644 return;
2645 }
2646
2647 if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
2648 SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
2649 {
2650 SubstituteFontFamily(FaceName, Level + 1);
2651 }
2652 }
2653
2654 static
2655 VOID
2656 FASTCALL
2657 IntFontType(PFONTGDI Font)
2658 {
2659 PS_FontInfoRec psfInfo;
2660 FT_ULong tmp_size = 0;
2661
2662 if (FT_HAS_MULTIPLE_MASTERS(Font->face))
2663 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
2664 if (FT_HAS_VERTICAL( Font->face ))
2665 Font->FontObj.flFontType |= FO_VERT_FACE;
2666 if (FT_IS_SCALABLE( Font->face ))
2667 Font->FontObj.flFontType |= FO_TYPE_RASTER;
2668 if (FT_IS_SFNT(Font->face))
2669 {
2670 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
2671 if (FT_Get_Sfnt_Table(Font->face, ft_sfnt_post))
2672 Font->FontObj.flFontType |= FO_POSTSCRIPT;
2673 }
2674 if (!FT_Get_PS_Font_Info(Font->face, &psfInfo ))
2675 {
2676 Font->FontObj.flFontType |= FO_POSTSCRIPT;
2677 }
2678 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
2679 if (!FT_Load_Sfnt_Table(Font->face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
2680 {
2681 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
2682 }
2683 }
2684
2685 NTSTATUS
2686 FASTCALL
2687 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
2688 {
2689 NTSTATUS Status = STATUS_SUCCESS;
2690 PTEXTOBJ TextObj;
2691 UNICODE_STRING FaceName;
2692 PPROCESSINFO Win32Process;
2693 UINT MatchScore;
2694
2695 if (!pTextObj)
2696 {
2697 TextObj = TEXTOBJ_LockText(FontHandle);
2698 if (NULL == TextObj)
2699 {
2700 return STATUS_INVALID_HANDLE;
2701 }
2702
2703 if (TextObj->fl & TEXTOBJECT_INIT)
2704 {
2705 TEXTOBJ_UnlockText(TextObj);
2706 return STATUS_SUCCESS;
2707 }
2708 }
2709 else
2710 TextObj = pTextObj;
2711
2712 if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName))
2713 {
2714 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
2715 return STATUS_NO_MEMORY;
2716 }
2717 SubstituteFontFamily(&FaceName, 0);
2718 MatchScore = 0;
2719 TextObj->Font = NULL;
2720
2721 /* First search private fonts */
2722 Win32Process = PsGetCurrentProcessWin32Process();
2723 IntLockProcessPrivateFonts(Win32Process);
2724 FindBestFontFromList(&TextObj->Font, &MatchScore,
2725 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
2726 &Win32Process->PrivateFontListHead);
2727 IntUnLockProcessPrivateFonts(Win32Process);
2728
2729 /* Search system fonts */
2730 IntLockGlobalFonts;
2731 FindBestFontFromList(&TextObj->Font, &MatchScore,
2732 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
2733 &FontListHead);
2734 IntUnLockGlobalFonts;
2735 if (NULL == TextObj->Font)
2736 {
2737 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
2738 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName);
2739 Status = STATUS_NOT_FOUND;
2740 }
2741 else
2742 {
2743 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
2744 // Need hdev, when freetype is loaded need to create DEVOBJ for
2745 // Consumer and Producer.
2746 TextObj->Font->iUniq = 1; // Now it can be cached.
2747 IntFontType(FontGdi);
2748 FontGdi->flType = TextObj->Font->flFontType;
2749 FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0;
2750 FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0;
2751 TextObj->fl |= TEXTOBJECT_INIT;
2752 Status = STATUS_SUCCESS;
2753 }
2754
2755 RtlFreeUnicodeString(&FaceName);
2756 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
2757
2758 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
2759
2760 return Status;
2761 }
2762
2763
2764 static
2765 BOOL
2766 FASTCALL
2767 IntGetFullFileName(
2768 POBJECT_NAME_INFORMATION NameInfo,
2769 ULONG Size,
2770 PUNICODE_STRING FileName)
2771 {
2772 NTSTATUS Status;
2773 OBJECT_ATTRIBUTES ObjectAttributes;
2774 HANDLE hFile;
2775 IO_STATUS_BLOCK IoStatusBlock;
2776 ULONG Desired;
2777
2778 InitializeObjectAttributes(&ObjectAttributes,
2779 FileName,
2780 OBJ_CASE_INSENSITIVE,
2781 NULL,
2782 NULL);
2783
2784 Status = ZwOpenFile(
2785 &hFile,
2786 0, // FILE_READ_ATTRIBUTES,
2787 &ObjectAttributes,
2788 &IoStatusBlock,
2789 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2790 0);
2791
2792 if (!NT_SUCCESS(Status))
2793 {
2794 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
2795 return FALSE;
2796 }
2797
2798 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
2799 ZwClose(hFile);
2800 if (!NT_SUCCESS(Status))
2801 {
2802 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
2803 return FALSE;
2804 }
2805
2806 return TRUE;
2807 }
2808
2809 BOOL
2810 FASTCALL
2811 IntGdiGetFontResourceInfo(
2812 PUNICODE_STRING FileName,
2813 PVOID pBuffer,
2814 DWORD *pdwBytes,
2815 DWORD dwType)
2816 {
2817 UNICODE_STRING EntryFileName;
2818 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
2819 PLIST_ENTRY ListEntry;
2820 PFONT_ENTRY FontEntry;
2821 FONTFAMILYINFO Info;
2822 ULONG Size;
2823 BOOL bFound = FALSE;
2824
2825 /* Create buffer for full path name */
2826 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
2827 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
2828 if (!NameInfo1)
2829 {
2830 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2831 return FALSE;
2832 }
2833
2834 /* Get the full path name */
2835 if (!IntGetFullFileName(NameInfo1, Size, FileName))
2836 {
2837 ExFreePool(NameInfo1);
2838 return FALSE;
2839 }
2840
2841 /* Create a buffer for the entries' names */
2842 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
2843 if (!NameInfo2)
2844 {
2845 ExFreePool(NameInfo1);
2846 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2847 return FALSE;
2848 }
2849
2850 /* Try to find the pathname in the global font list */
2851 IntLockGlobalFonts;
2852 for (ListEntry = FontListHead.Flink;
2853 ListEntry != &FontListHead;
2854 ListEntry = ListEntry->Flink)
2855 {
2856 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
2857 if (FontEntry->Font->Filename != NULL)
2858 {
2859 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
2860 if (IntGetFullFileName(NameInfo2, Size, &EntryFileName))
2861 {
2862 if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
2863 {
2864 /* Found */
2865 FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font);
2866 bFound = TRUE;
2867 break;
2868 }
2869 }
2870 }
2871 }
2872 IntUnLockGlobalFonts;
2873
2874 /* Free the buffers */
2875 ExFreePool(NameInfo1);
2876 ExFreePool(NameInfo2);
2877
2878 if (!bFound && dwType != 5)
2879 {
2880 /* Font could not be found in system table
2881 dwType == 5 will still handle this */
2882 return FALSE;
2883 }
2884
2885 switch (dwType)
2886 {
2887 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
2888 *(DWORD*)pBuffer = 1;
2889 *pdwBytes = sizeof(DWORD);
2890 break;
2891
2892 case 1: /* Copy the full font name */
2893 Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1;
2894 Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR);
2895 RtlCopyMemory(pBuffer, Info.EnumLogFontEx.elfFullName, Size);
2896 // FIXME: Do we have to zeroterminate?
2897 *pdwBytes = Size;
2898 break;
2899
2900 case 2: /* Copy a LOGFONTW structure */
2901 Info.EnumLogFontEx.elfLogFont.lfWidth = 0;
2902 RtlCopyMemory(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
2903 *pdwBytes = sizeof(LOGFONTW);
2904 break;
2905
2906 case 3: /* FIXME: What exactly is copied here? */
2907 *(DWORD*)pBuffer = 1;
2908 *pdwBytes = sizeof(DWORD*);
2909 break;
2910
2911 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
2912 *(BOOL*)pBuffer = !bFound;
2913 *pdwBytes = sizeof(BOOL);
2914 break;
2915
2916 default:
2917 return FALSE;
2918 }
2919
2920 return TRUE;
2921 }
2922
2923
2924 BOOL
2925 FASTCALL
2926 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
2927 {
2928 if (FT_HAS_FIXED_SIZES(Font->face))
2929 Info->iTechnology = RI_TECH_BITMAP;
2930 else
2931 {
2932 if (FT_IS_SCALABLE(Font->face))
2933 Info->iTechnology = RI_TECH_SCALABLE;
2934 else
2935 Info->iTechnology = RI_TECH_FIXED;
2936 }
2937 Info->iUniq = Font->FontObj.iUniq;
2938 Info->dwUnknown = -1;
2939 return TRUE;
2940 }
2941
2942
2943 DWORD
2944 FASTCALL
2945 ftGdiGetKerningPairs( PFONTGDI Font,
2946 DWORD cPairs,
2947 LPKERNINGPAIR pKerningPair)
2948 {
2949 DWORD Count = 0;
2950 INT i = 0;
2951 FT_Face face = Font->face;
2952
2953 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
2954 {
2955 FT_UInt previous_index = 0, glyph_index = 0;
2956 FT_ULong char_code, char_previous;
2957 FT_Vector delta;
2958
2959 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
2960
2961 IntLockFreeType;
2962
2963 while (glyph_index)
2964 {
2965 if (previous_index && glyph_index)
2966 {
2967 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
2968
2969 if (pKerningPair && cPairs)
2970 {
2971 pKerningPair[i].wFirst = char_previous;
2972 pKerningPair[i].wSecond = char_code;
2973 pKerningPair[i].iKernAmount = delta.x;
2974 i++;
2975 if (i == cPairs) break;
2976 }
2977 Count++;
2978 }
2979 previous_index = glyph_index;
2980 char_previous = char_code;
2981 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
2982 }
2983 IntUnLockFreeType;
2984 }
2985 return Count;
2986 }
2987
2988
2989 ///////////////////////////////////////////////////////////////////////////
2990 //
2991 // Functions needing sorting.
2992 //
2993 ///////////////////////////////////////////////////////////////////////////
2994 int APIENTRY
2995 NtGdiGetFontFamilyInfo(HDC Dc,
2996 LPLOGFONTW UnsafeLogFont,
2997 PFONTFAMILYINFO UnsafeInfo,
2998 DWORD Size)
2999 {
3000 NTSTATUS Status;
3001 LOGFONTW LogFont;
3002 PFONTFAMILYINFO Info;
3003 DWORD Count;
3004 PPROCESSINFO Win32Process;
3005
3006 /* Make a safe copy */
3007 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
3008 if (! NT_SUCCESS(Status))
3009 {
3010 EngSetLastError(ERROR_INVALID_PARAMETER);
3011 return -1;
3012 }
3013
3014 /* Allocate space for a safe copy */
3015 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT);
3016 if (NULL == Info)
3017 {
3018 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3019 return -1;
3020 }
3021
3022 /* Enumerate font families in the global list */
3023 IntLockGlobalFonts;
3024 Count = 0;
3025 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
3026 {
3027 IntUnLockGlobalFonts;
3028 ExFreePool(Info);
3029 return -1;
3030 }
3031 IntUnLockGlobalFonts;
3032
3033 /* Enumerate font families in the process local list */
3034 Win32Process = PsGetCurrentProcessWin32Process();
3035 IntLockProcessPrivateFonts(Win32Process);
3036 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
3037 &Win32Process->PrivateFontListHead))
3038 {
3039 IntUnLockProcessPrivateFonts(Win32Process);
3040 ExFreePool(Info);
3041 return -1;
3042 }
3043 IntUnLockProcessPrivateFonts(Win32Process);
3044
3045 /* Enumerate font families in the registry */
3046 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
3047 {
3048 ExFreePool(Info);
3049 return -1;
3050 }
3051
3052 /* Return data to caller */
3053 if (0 != Count)
3054 {
3055 Status = MmCopyToCaller(UnsafeInfo, Info,
3056 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
3057 if (! NT_SUCCESS(Status))
3058 {
3059 ExFreePool(Info);
3060 EngSetLastError(ERROR_INVALID_PARAMETER);
3061 return -1;
3062 }
3063 }
3064
3065 ExFreePool(Info);
3066
3067 return Count;
3068 }
3069
3070 BOOL
3071 APIENTRY
3072 GreExtTextOutW(
3073 IN HDC hDC,
3074 IN INT XStart,
3075 IN INT YStart,
3076 IN UINT fuOptions,
3077 IN OPTIONAL PRECTL lprc,
3078 IN LPWSTR String,
3079 IN INT Count,
3080 IN OPTIONAL LPINT Dx,
3081 IN DWORD dwCodePage)
3082 {
3083 /*
3084 * FIXME:
3085 * Call EngTextOut, which does the real work (calling DrvTextOut where
3086 * appropriate)
3087 */
3088
3089 DC *dc;
3090 PDC_ATTR pdcattr;
3091 SURFOBJ *SurfObj;
3092 SURFACE *psurf = NULL;
3093 int error, glyph_index, n, i;
3094 FT_Face face;
3095 FT_GlyphSlot glyph;
3096 FT_BitmapGlyph realglyph;
3097 LONGLONG TextLeft, RealXStart;
3098 ULONG TextTop, previous, BackgroundLeft;
3099 FT_Bool use_kerning;
3100 RECTL DestRect, MaskRect, DummyRect = {0, 0, 0, 0};
3101 POINTL SourcePoint, BrushOrigin;
3102 HBITMAP HSourceGlyph;
3103 SURFOBJ *SourceGlyphSurf;
3104 SIZEL bitSize;
3105 FT_CharMap found = 0, charmap;
3106 INT yoff;
3107 FONTOBJ *FontObj;
3108 PFONTGDI FontGDI;
3109 PTEXTOBJ TextObj = NULL;
3110 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
3111 FT_Render_Mode RenderMode;
3112 BOOLEAN Render;
3113 POINT Start;
3114 BOOL DoBreak = FALSE;
3115 USHORT DxShift;
3116
3117 // TODO: Write test-cases to exactly match real Windows in different
3118 // bad parameters (e.g. does Windows check the DC or the RECT first?).
3119 dc = DC_LockDc(hDC);
3120 if (!dc)
3121 {
3122 EngSetLastError(ERROR_INVALID_HANDLE);
3123 return FALSE;
3124 }
3125 if (dc->dctype == DC_TYPE_INFO)
3126 {
3127 DC_UnlockDc(dc);
3128 /* Yes, Windows really returns TRUE in this case */
3129 return TRUE;
3130 }
3131
3132 pdcattr = dc->pdcattr;
3133
3134 if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE)
3135 {
3136 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
3137 DC_vUpdateBackgroundBrush(dc);
3138 }
3139
3140 /* Check if String is valid */
3141 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
3142 {
3143 EngSetLastError(ERROR_INVALID_PARAMETER);
3144 goto fail;
3145 }
3146
3147 DxShift = fuOptions & ETO_PDY ? 1 : 0;
3148
3149 if (PATH_IsPathOpen(dc->dclevel))
3150 {
3151 if (!PATH_ExtTextOut( dc,
3152 XStart,
3153 YStart,
3154 fuOptions,
3155 (const RECTL *)lprc,
3156 String,
3157 Count,
3158 (const INT *)Dx)) goto fail;
3159 goto good;
3160 }
3161
3162 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
3163 {
3164 IntLPtoDP(dc, (POINT *)lprc, 2);
3165 }
3166
3167 Start.x = XStart;
3168 Start.y = YStart;
3169 IntLPtoDP(dc, &Start, 1);
3170
3171 RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;
3172 YStart = Start.y + dc->ptlDCOrig.y;
3173
3174 SourcePoint.x = 0;
3175 SourcePoint.y = 0;
3176 MaskRect.left = 0;
3177 MaskRect.top = 0;
3178 BrushOrigin.x = 0;
3179 BrushOrigin.y = 0;
3180
3181 if ((fuOptions & ETO_OPAQUE) && lprc)
3182 {
3183 DestRect.left = lprc->left;
3184 DestRect.top = lprc->top;
3185 DestRect.right = lprc->right;
3186 DestRect.bottom = lprc->bottom;
3187
3188 DestRect.left += dc->ptlDCOrig.x;
3189 DestRect.top += dc->ptlDCOrig.y;
3190 DestRect.right += dc->ptlDCOrig.x;
3191 DestRect.bottom += dc->ptlDCOrig.y;
3192
3193 DC_vPrepareDCsForBlit(dc, DestRect, NULL, DestRect);
3194
3195 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
3196 DC_vUpdateBackgroundBrush(dc);
3197
3198 IntEngBitBlt(
3199 &dc->dclevel.pSurface->SurfObj,
3200 NULL,
3201 NULL,
3202 dc->rosdc.CombinedClip,
3203 NULL,
3204 &DestRect,
3205 &SourcePoint,
3206 &SourcePoint,
3207 &dc->eboBackground.BrushObject,
3208 &BrushOrigin,
3209 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
3210 fuOptions &= ~ETO_OPAQUE;
3211 DC_vFinishBlit(dc, NULL);
3212 }
3213 else
3214 {
3215 if (pdcattr->jBkMode == OPAQUE)
3216 {
3217 fuOptions |= ETO_OPAQUE;
3218 }
3219 }
3220
3221 TextObj = RealizeFontInit(pdcattr->hlfntNew);
3222 if (TextObj == NULL)
3223 {
3224 goto fail;
3225 }
3226
3227 FontObj = TextObj->Font;
3228 ASSERT(FontObj);
3229 FontGDI = ObjToGDI(FontObj, FONT);
3230 ASSERT(FontGDI);
3231
3232 IntLockFreeType;
3233 face = FontGDI->face;
3234 if (face->charmap == NULL)
3235 {
3236 DPRINT("WARNING: No charmap selected!\n");
3237 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3238
3239 for (n = 0; n < face->num_charmaps; n++)
3240 {
3241 charmap = face->charmaps[n];
3242 DPRINT("Found charmap encoding: %u\n", charmap->encoding);
3243 if (charmap->encoding != 0)
3244 {
3245 found = charmap;
3246 break;
3247 }
3248 }
3249 if (!found)
3250 {
3251 DPRINT1("WARNING: Could not find desired charmap!\n");
3252 }
3253 error = FT_Set_Charmap(face, found);
3254 if (error)
3255 {
3256 DPRINT1("WARNING: Could not set the charmap!\n");
3257 }
3258 }
3259
3260 Render = IntIsFontRenderingEnabled();
3261 if (Render)
3262 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
3263 else
3264 RenderMode = FT_RENDER_MODE_MONO;
3265
3266 error = FT_Set_Pixel_Sizes(
3267 face,
3268 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
3269 /* FIXME: Should set character height if neg */
3270 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
3271 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
3272 if (error)
3273 {
3274 DPRINT1("Error in setting pixel sizes: %u\n", error);
3275 IntUnLockFreeType;
3276 goto fail;
3277 }
3278
3279 /*
3280 * Process the vertical alignment and determine the yoff.
3281 */
3282
3283 if (pdcattr->lTextAlign & TA_BASELINE)
3284 yoff = 0;
3285 else if (pdcattr->lTextAlign & TA_BOTTOM)
3286 yoff = -face->size->metrics.descender >> 6;
3287 else /* TA_TOP */
3288 yoff = face->size->metrics.ascender >> 6;
3289
3290 use_kerning = FT_HAS_KERNING(face);
3291 previous = 0;
3292
3293 /*
3294 * Process the horizontal alignment and modify XStart accordingly.
3295 */
3296
3297 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
3298 {
3299 ULONGLONG TextWidth = 0;
3300 LPCWSTR TempText = String;
3301 int Start;
3302
3303 /*
3304 * Calculate width of the text.
3305 */
3306
3307 if (NULL != Dx)
3308 {
3309 Start = Count < 2 ? 0 : Count - 2;
3310 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
3311 }
3312 else
3313 {
3314 Start = 0;
3315 }
3316 TempText = String + Start;
3317
3318 for (i = Start; i < Count; i++)
3319 {
3320 if (fuOptions & ETO_GLYPH_INDEX)
3321 glyph_index = *TempText;
3322 else
3323 glyph_index = FT_Get_Char_Index(face, *TempText);
3324
3325 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3326 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
3327 {
3328 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3329 if (error)
3330 {
3331 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3332 }
3333
3334 glyph = face->glyph;
3335 realglyph = ftGdiGlyphCacheSet(face, glyph_index,
3336 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
3337 if (!realglyph)
3338 {
3339 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
3340 IntUnLockFreeType;
3341 goto fail;
3342 }
3343
3344 }
3345 /* Retrieve kerning distance */
3346 if (use_kerning && previous && glyph_index)
3347 {
3348 FT_Vector delta;
3349 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3350 TextWidth += delta.x;
3351 }
3352
3353 TextWidth += realglyph->root.advance.x >> 10;
3354
3355 previous = glyph_index;
3356 TempText++;
3357 }
3358
3359 previous = 0;
3360
3361 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
3362 {
3363 RealXStart -= TextWidth / 2;
3364 }
3365 else
3366 {
3367 RealXStart -= TextWidth;
3368 }
3369 }
3370
3371 TextLeft = RealXStart;
3372 TextTop = YStart;
3373 BackgroundLeft = (RealXStart + 32) >> 6;
3374
3375 /* Lock blit with a dummy rect */
3376 DC_vPrepareDCsForBlit(dc, DummyRect, NULL, DummyRect);
3377
3378 psurf = dc->dclevel.pSurface ;
3379 SurfObj = &psurf->SurfObj ;
3380
3381 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
3382 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
3383
3384 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
3385 DC_vUpdateBackgroundBrush(dc) ;
3386
3387 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
3388 DC_vUpdateTextBrush(dc) ;
3389
3390 /*
3391 * The main rendering loop.
3392 */
3393 for (i = 0; i < Count; i++)
3394 {
3395 if (fuOptions & ETO_GLYPH_INDEX)
3396 glyph_index = *String;
3397 else
3398 glyph_index = FT_Get_Char_Index(face, *String);
3399
3400 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3401 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
3402 {
3403 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3404 if (error)
3405 {
3406 DPRINT1("Failed to load and render glyph! [index: %u]\n", glyph_index);
3407 IntUnLockFreeType;
3408 goto fail2;
3409 }
3410 glyph = face->glyph;
3411 realglyph = ftGdiGlyphCacheSet(face,
3412 glyph_index,
3413 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3414 glyph,
3415 RenderMode);
3416 if (!realglyph)
3417 {
3418 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
3419 IntUnLockFreeType;
3420 goto fail2;
3421 }
3422 }
3423
3424 /* retrieve kerning distance and move pen position */
3425 if (use_kerning && previous && glyph_index && NULL == Dx)
3426 {
3427 FT_Vector delta;
3428 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);