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