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