[YAROTOWS] Reintegrate the branch. For a brighter future.
[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 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
372 return 0;
373 }
374
375 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), TAG_FONTOBJ);
376 if (FontGDI == NULL)
377 {
378 FT_Done_Face(Face);
379 ObDereferenceObject(SectionObject);
380 ExFreePoolWithTag(Entry, TAG_FONT);
381 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
382 return 0;
383 }
384
385 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, FileName->Length + sizeof(WCHAR), TAG_PFF);
386 if (FontGDI->Filename == NULL)
387 {
388 EngFreeMem(FontGDI);
389 FT_Done_Face(Face);
390 ObDereferenceObject(SectionObject);
391 ExFreePoolWithTag(Entry, TAG_FONT);
392 SetLastWin32Error(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, TAG_GDITEXT);
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, TAG_GDITEXT);
1080
1081 wcsncpy(Info->EnumLogFontEx.elfLogFont.lfFaceName, FaceName, LF_FACESIZE);
1082 wcsncpy(Info->EnumLogFontEx.elfFullName, FaceName, LF_FULLFACESIZE);
1083 RtlInitAnsiString(&StyleA, FontGDI->face->style_name);
1084 RtlAnsiStringToUnicodeString(&StyleW, &StyleA, TRUE);
1085 wcsncpy(Info->EnumLogFontEx.elfStyle, StyleW.Buffer, LF_FACESIZE);
1086 RtlFreeUnicodeString(&StyleW);
1087
1088 Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
1089 Info->EnumLogFontEx.elfScript[0] = L'\0';
1090 IntLockFreeType;
1091 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
1092 IntUnLockFreeType;
1093 if (NULL != pOS2)
1094 {
1095 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1096 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1097 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1098 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1099 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1100 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1101
1102 if (0 == pOS2->version)
1103 {
1104 FT_UInt Dummy;
1105
1106 if (FT_Get_First_Char(FontGDI->face, &Dummy) < 0x100)
1107 fs.fsCsb[0] |= FS_LATIN1;
1108 else
1109 fs.fsCsb[0] |= FS_SYMBOL;
1110 }
1111 if (fs.fsCsb[0] == 0)
1112 { /* let's see if we can find any interesting cmaps */
1113 for (i = 0; i < FontGDI->face->num_charmaps; i++)
1114 {
1115 switch (FontGDI->face->charmaps[i]->encoding)
1116 {
1117 case FT_ENCODING_UNICODE:
1118 case FT_ENCODING_APPLE_ROMAN:
1119 fs.fsCsb[0] |= FS_LATIN1;
1120 break;
1121 case FT_ENCODING_MS_SYMBOL:
1122 fs.fsCsb[0] |= FS_SYMBOL;
1123 break;
1124 default:
1125 break;
1126 }
1127 }
1128 }
1129 for (i = 0; i < MAXTCIINDEX; i++)
1130 {
1131 fs0 = 1L << i;
1132 if (fs.fsCsb[0] & fs0)
1133 {
1134 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
1135 {
1136 CharSetInfo.ciCharset = DEFAULT_CHARSET;
1137 }
1138 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
1139 {
1140 Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
1141 if (NULL != ElfScripts[i])
1142 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
1143 else
1144 {
1145 DPRINT1("Unknown elfscript for bit %d\n", i);
1146 }
1147 }
1148 }
1149 }
1150 Info->NewTextMetricEx.ntmFontSig = fs;
1151 }
1152 }
1153
1154 static int FASTCALL
1155 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
1156 {
1157 DWORD i;
1158 UNICODE_STRING InfoFaceName;
1159
1160 for (i = 0; i < InfoEntries; i++)
1161 {
1162 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
1163 if (0 == RtlCompareUnicodeString(&InfoFaceName, FaceName, TRUE))
1164 {
1165 return i;
1166 }
1167 }
1168
1169 return -1;
1170 }
1171
1172 static BOOLEAN FASTCALL
1173 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
1174 PFONTFAMILYINFO Info, DWORD InfoEntries)
1175 {
1176 UNICODE_STRING LogFontFaceName;
1177
1178 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
1179 if (0 != LogFontFaceName.Length
1180 && 0 != RtlCompareUnicodeString(&LogFontFaceName, FaceName, TRUE))
1181 {
1182 return FALSE;
1183 }
1184
1185 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
1186 }
1187
1188 static BOOLEAN FASTCALL
1189 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
1190 PFONTFAMILYINFO Info,
1191 DWORD *Count,
1192 DWORD Size,
1193 PLIST_ENTRY Head)
1194 {
1195 PLIST_ENTRY Entry;
1196 PFONT_ENTRY CurrentEntry;
1197 ANSI_STRING EntryFaceNameA;
1198 UNICODE_STRING EntryFaceNameW;
1199 FONTGDI *FontGDI;
1200
1201 Entry = Head->Flink;
1202 while (Entry != Head)
1203 {
1204 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1205
1206 FontGDI = CurrentEntry->Font;
1207 ASSERT(FontGDI);
1208
1209 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
1210 RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
1211 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
1212 {
1213 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
1214 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
1215 }
1216
1217 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
1218 {
1219 if (*Count < Size)
1220 {
1221 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
1222 }
1223 (*Count)++;
1224 }
1225 RtlFreeUnicodeString(&EntryFaceNameW);
1226 Entry = Entry->Flink;
1227 }
1228
1229 return TRUE;
1230 }
1231
1232 typedef struct FontFamilyInfoCallbackContext
1233 {
1234 LPLOGFONTW LogFont;
1235 PFONTFAMILYINFO Info;
1236 DWORD Count;
1237 DWORD Size;
1238 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
1239
1240 static NTSTATUS APIENTRY
1241 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
1242 IN PVOID ValueData, IN ULONG ValueLength,
1243 IN PVOID Context, IN PVOID EntryContext)
1244 {
1245 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
1246 UNICODE_STRING RegistryName, RegistryValue;
1247 int Existing;
1248 PFONTGDI FontGDI;
1249
1250 if (REG_SZ != ValueType)
1251 {
1252 return STATUS_SUCCESS;
1253 }
1254 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
1255 RtlInitUnicodeString(&RegistryName, ValueName);
1256
1257 /* Do we need to include this font family? */
1258 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
1259 min(InfoContext->Count, InfoContext->Size)))
1260 {
1261 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
1262 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
1263 min(InfoContext->Count, InfoContext->Size));
1264 if (0 <= Existing)
1265 {
1266 /* We already have the information about the "real" font. Just copy it */
1267 if (InfoContext->Count < InfoContext->Size)
1268 {
1269 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
1270 wcsncpy(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
1271 RegistryName.Buffer, LF_FACESIZE);
1272 }
1273 InfoContext->Count++;
1274 return STATUS_SUCCESS;
1275 }
1276
1277 /* Try to find information about the "real" font */
1278 FontGDI = FindFaceNameInLists(&RegistryValue);
1279 if (NULL == FontGDI)
1280 {
1281 /* "Real" font not found, discard this registry entry */
1282 return STATUS_SUCCESS;
1283 }
1284
1285 /* Return info about the "real" font but with the name of the alias */
1286 if (InfoContext->Count < InfoContext->Size)
1287 {
1288 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
1289 RegistryName.Buffer, FontGDI);
1290 }
1291 InfoContext->Count++;
1292 return STATUS_SUCCESS;
1293 }
1294
1295 return STATUS_SUCCESS;
1296 }
1297
1298 static BOOLEAN FASTCALL
1299 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
1300 PFONTFAMILYINFO Info,
1301 DWORD *Count,
1302 DWORD Size)
1303 {
1304 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
1305 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
1306 NTSTATUS Status;
1307
1308 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\SysFontSubstitutes
1309 The real work is done in the registry callback function */
1310 Context.LogFont = LogFont;
1311 Context.Info = Info;
1312 Context.Count = *Count;
1313 Context.Size = Size;
1314
1315 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
1316 QueryTable[0].Flags = 0;
1317 QueryTable[0].Name = NULL;
1318 QueryTable[0].EntryContext = NULL;
1319 QueryTable[0].DefaultType = REG_NONE;
1320 QueryTable[0].DefaultData = NULL;
1321 QueryTable[0].DefaultLength = 0;
1322
1323 QueryTable[1].QueryRoutine = NULL;
1324 QueryTable[1].Name = NULL;
1325
1326 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
1327 L"SysFontSubstitutes",
1328 QueryTable,
1329 &Context,
1330 NULL);
1331 if (NT_SUCCESS(Status))
1332 {
1333 *Count = Context.Count;
1334 }
1335
1336 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
1337 }
1338
1339 BOOL
1340 FASTCALL
1341 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
1342 {
1343 if ( lprs )
1344 {
1345 lprs->nSize = sizeof(RASTERIZER_STATUS);
1346 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
1347 lprs->nLanguageID = gusLanguageID;
1348 return TRUE;
1349 }
1350 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1351 return FALSE;
1352 }
1353
1354
1355 FT_BitmapGlyph APIENTRY
1356 ftGdiGlyphCacheGet(
1357 FT_Face Face,
1358 INT GlyphIndex,
1359 INT Height)
1360 {
1361 PLIST_ENTRY CurrentEntry;
1362 PFONT_CACHE_ENTRY FontEntry;
1363
1364 CurrentEntry = FontCacheListHead.Flink;
1365 while (CurrentEntry != &FontCacheListHead)
1366 {
1367 FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
1368 if (FontEntry->Face == Face &&
1369 FontEntry->GlyphIndex == GlyphIndex &&
1370 FontEntry->Height == Height)
1371 break;
1372 CurrentEntry = CurrentEntry->Flink;
1373 }
1374
1375 if (CurrentEntry == &FontCacheListHead)
1376 {
1377 return NULL;
1378 }
1379
1380 RemoveEntryList(CurrentEntry);
1381 InsertHeadList(&FontCacheListHead, CurrentEntry);
1382 return FontEntry->BitmapGlyph;
1383 }
1384
1385 FT_BitmapGlyph APIENTRY
1386 ftGdiGlyphCacheSet(
1387 FT_Face Face,
1388 INT GlyphIndex,
1389 INT Height,
1390 FT_GlyphSlot GlyphSlot,
1391 FT_Render_Mode RenderMode)
1392 {
1393 FT_Glyph GlyphCopy;
1394 INT error;
1395 PFONT_CACHE_ENTRY NewEntry;
1396 FT_Bitmap AlignedBitmap;
1397 FT_BitmapGlyph BitmapGlyph;
1398
1399 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
1400 if (error)
1401 {
1402 DPRINT1("Failure caching glyph.\n");
1403 return NULL;
1404 };
1405
1406 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
1407 if (error)
1408 {
1409 DPRINT1("Failure rendering glyph.\n");
1410 return NULL;
1411 };
1412
1413 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
1414 if (!NewEntry)
1415 {
1416 DPRINT1("Alloc failure caching glyph.\n");
1417 FT_Done_Glyph(GlyphCopy);
1418 return NULL;
1419 }
1420
1421 BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
1422 FT_Bitmap_New(&AlignedBitmap);
1423 if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
1424 {
1425 DPRINT1("Conversion failed\n");
1426 FT_Done_Glyph((FT_Glyph)BitmapGlyph);
1427 return NULL;
1428 }
1429
1430 FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
1431 BitmapGlyph->bitmap = AlignedBitmap;
1432
1433 NewEntry->GlyphIndex = GlyphIndex;
1434 NewEntry->Face = Face;
1435 NewEntry->BitmapGlyph = BitmapGlyph;
1436 NewEntry->Height = Height;
1437
1438 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
1439 if (FontCacheNumEntries++ > MAX_FONT_CACHE)
1440 {
1441 NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
1442 FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph);
1443 RemoveTailList(&FontCacheListHead);
1444 ExFreePool(NewEntry);
1445 FontCacheNumEntries--;
1446 }
1447
1448 return BitmapGlyph;
1449 }
1450
1451
1452 static
1453 void
1454 FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1455 {
1456 pt->x.value = vec->x >> 6;
1457 pt->x.fract = (vec->x & 0x3f) << 10;
1458 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1459 pt->y.value = vec->y >> 6;
1460 pt->y.fract = (vec->y & 0x3f) << 10;
1461 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1462 return;
1463 }
1464
1465 /*
1466 This function builds an FT_Fixed from a float. It puts the integer part
1467 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
1468 It fails if the integer part of the float number is greater than SHORT_MAX.
1469 */
1470 static __inline FT_Fixed FT_FixedFromFloat(float f)
1471 {
1472 short value = f;
1473 unsigned short fract = (f - value) * 0xFFFF;
1474 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
1475 }
1476
1477 /*
1478 This function builds an FT_Fixed from a FIXED. It simply put f.value
1479 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
1480 */
1481 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
1482 {
1483 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
1484 }
1485
1486 /*
1487 * Based on WineEngGetGlyphOutline
1488 *
1489 */
1490 ULONG
1491 FASTCALL
1492 ftGdiGetGlyphOutline(
1493 PDC dc,
1494 WCHAR wch,
1495 UINT iFormat,
1496 LPGLYPHMETRICS pgm,
1497 ULONG cjBuf,
1498 PVOID pvBuf,
1499 LPMAT2 pmat2,
1500 BOOL bIgnoreRotation)
1501 {
1502 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
1503 PDC_ATTR pdcattr;
1504 PTEXTOBJ TextObj;
1505 PFONTGDI FontGDI;
1506 HFONT hFont = 0;
1507 GLYPHMETRICS gm;
1508 ULONG Size;
1509 FT_Face ft_face;
1510 FT_UInt glyph_index;
1511 DWORD width, height, pitch, needed = 0;
1512 FT_Bitmap ft_bitmap;
1513 FT_Error error;
1514 INT left, right, top = 0, bottom = 0;
1515 FT_Angle angle = 0;
1516 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
1517 FLOAT eM11, widthRatio = 1.0;
1518 FT_Matrix transMat = identityMat;
1519 BOOL needsTransform = FALSE;
1520 INT orientation;
1521 LONG aveWidth;
1522 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
1523 OUTLINETEXTMETRICW *potm;
1524 int n = 0;
1525 FT_CharMap found = 0, charmap;
1526 XFORM xForm;
1527
1528 DPRINT("%d, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
1529 cjBuf, pvBuf, pmat2);
1530
1531 pdcattr = dc->pdcattr;
1532
1533 MatrixS2XForm(&xForm, &dc->dclevel.mxWorldToDevice);
1534 eM11 = xForm.eM11;
1535
1536 hFont = pdcattr->hlfntNew;
1537 TextObj = RealizeFontInit(hFont);
1538
1539 if (!TextObj)
1540 {
1541 SetLastWin32Error(ERROR_INVALID_HANDLE);
1542 return GDI_ERROR;
1543 }
1544 FontGDI = ObjToGDI(TextObj->Font, FONT);
1545 ft_face = FontGDI->face;
1546
1547 aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth: 0;
1548 orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation: 0;
1549
1550 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
1551 potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
1552 if (!potm)
1553 {
1554 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1555 TEXTOBJ_UnlockText(TextObj);
1556 return GDI_ERROR;
1557 }
1558 IntGetOutlineTextMetrics(FontGDI, Size, potm);
1559
1560 IntLockFreeType;
1561
1562 /* During testing, I never saw this used. In here just incase.*/
1563 if (ft_face->charmap == NULL)
1564 {
1565 DPRINT("WARNING: No charmap selected!\n");
1566 DPRINT("This font face has %d charmaps\n", ft_face->num_charmaps);
1567
1568 for (n = 0; n < ft_face->num_charmaps; n++)
1569 {
1570 charmap = ft_face->charmaps[n];
1571 DPRINT("found charmap encoding: %u\n", charmap->encoding);
1572 if (charmap->encoding != 0)
1573 {
1574 found = charmap;
1575 break;
1576 }
1577 }
1578 if (!found)
1579 {
1580 DPRINT1("WARNING: Could not find desired charmap!\n");
1581 }
1582 error = FT_Set_Charmap(ft_face, found);
1583 if (error)
1584 {
1585 DPRINT1("WARNING: Could not set the charmap!\n");
1586 }
1587 }
1588
1589 // FT_Set_Pixel_Sizes(ft_face,
1590 // TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
1591 /* FIXME should set character height if neg */
1592 // (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
1593 // TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
1594
1595 TEXTOBJ_UnlockText(TextObj);
1596
1597 if (iFormat & GGO_GLYPH_INDEX)
1598 {
1599 glyph_index = wch;
1600 iFormat &= ~GGO_GLYPH_INDEX;
1601 }
1602 else glyph_index = FT_Get_Char_Index(ft_face, wch);
1603
1604 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
1605 load_flags |= FT_LOAD_NO_BITMAP;
1606
1607 if (iFormat & GGO_UNHINTED)
1608 {
1609 load_flags |= FT_LOAD_NO_HINTING;
1610 iFormat &= ~GGO_UNHINTED;
1611 }
1612
1613 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
1614 if (error)
1615 {
1616 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1617 IntUnLockFreeType;
1618 if (potm) ExFreePoolWithTag(potm, TAG_GDITEXT);
1619 return GDI_ERROR;
1620 }
1621 IntUnLockFreeType;
1622
1623 if (aveWidth && potm)
1624 {
1625 widthRatio = (FLOAT)aveWidth * eM11 /
1626 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
1627 }
1628
1629 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
1630 right = (INT)((ft_face->glyph->metrics.horiBearingX +
1631 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
1632
1633 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
1634 lsb = left >> 6;
1635 bbx = (right - left) >> 6;
1636
1637 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
1638
1639 IntLockFreeType;
1640
1641 /* Scaling transform */
1642 if (aveWidth)
1643 {
1644 FT_Matrix scaleMat;
1645 DPRINT("Scaling Trans!\n");
1646 scaleMat.xx = FT_FixedFromFloat(widthRatio);
1647 scaleMat.xy = 0;
1648 scaleMat.yx = 0;
1649 scaleMat.yy = (1 << 16);
1650 FT_Matrix_Multiply(&scaleMat, &transMat);
1651 needsTransform = TRUE;
1652 }
1653
1654 /* Slant transform */
1655 if (potm->otmTextMetrics.tmItalic)
1656 {
1657 FT_Matrix slantMat;
1658 DPRINT("Slant Trans!\n");
1659 slantMat.xx = (1 << 16);
1660 slantMat.xy = ((1 << 16) >> 2);
1661 slantMat.yx = 0;
1662 slantMat.yy = (1 << 16);
1663 FT_Matrix_Multiply(&slantMat, &transMat);
1664 needsTransform = TRUE;
1665 }
1666
1667 /* Rotation transform */
1668 if (orientation)
1669 {
1670 FT_Matrix rotationMat;
1671 FT_Vector vecAngle;
1672 DPRINT("Rotation Trans!\n");
1673 angle = FT_FixedFromFloat((float)orientation / 10.0);
1674 FT_Vector_Unit(&vecAngle, angle);
1675 rotationMat.xx = vecAngle.x;
1676 rotationMat.xy = -vecAngle.y;
1677 rotationMat.yx = -rotationMat.xy;
1678 rotationMat.yy = rotationMat.xx;
1679 FT_Matrix_Multiply(&rotationMat, &transMat);
1680 needsTransform = TRUE;
1681 }
1682
1683 /* Extra transformation specified by caller */
1684 if (pmat2)
1685 {
1686 FT_Matrix extraMat;
1687 DPRINT("MAT2 Matrix Trans!\n");
1688 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
1689 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
1690 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
1691 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
1692 FT_Matrix_Multiply(&extraMat, &transMat);
1693 needsTransform = TRUE;
1694 }
1695
1696 if (potm) ExFreePoolWithTag(potm, TAG_GDITEXT); /* It looks like we are finished with potm ATM.*/
1697
1698 if (!needsTransform)
1699 {
1700 DPRINT("No Need to be Transformed!\n");
1701 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1702 bottom = (ft_face->glyph->metrics.horiBearingY -
1703 ft_face->glyph->metrics.height) & -64;
1704 gm.gmCellIncX = adv;
1705 gm.gmCellIncY = 0;
1706 }
1707 else
1708 {
1709 INT xc, yc;
1710 FT_Vector vec;
1711 for (xc = 0; xc < 2; xc++)
1712 {
1713 for (yc = 0; yc < 2; yc++)
1714 {
1715 vec.x = (ft_face->glyph->metrics.horiBearingX +
1716 xc * ft_face->glyph->metrics.width);
1717 vec.y = ft_face->glyph->metrics.horiBearingY -
1718 yc * ft_face->glyph->metrics.height;
1719 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
1720 FT_Vector_Transform(&vec, &transMat);
1721 if (xc == 0 && yc == 0)
1722 {
1723 left = right = vec.x;
1724 top = bottom = vec.y;
1725 }
1726 else
1727 {
1728 if (vec.x < left) left = vec.x;
1729 else if (vec.x > right) right = vec.x;
1730 if (vec.y < bottom) bottom = vec.y;
1731 else if (vec.y > top) top = vec.y;
1732 }
1733 }
1734 }
1735 left = left & -64;
1736 right = (right + 63) & -64;
1737 bottom = bottom & -64;
1738 top = (top + 63) & -64;
1739
1740 DPRINT("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1741 vec.x = ft_face->glyph->metrics.horiAdvance;
1742 vec.y = 0;
1743 FT_Vector_Transform(&vec, &transMat);
1744 gm.gmCellIncX = (vec.x+63) >> 6;
1745 gm.gmCellIncY = -((vec.y+63) >> 6);
1746 }
1747 gm.gmBlackBoxX = (right - left) >> 6;
1748 gm.gmBlackBoxY = (top - bottom) >> 6;
1749 gm.gmptGlyphOrigin.x = left >> 6;
1750 gm.gmptGlyphOrigin.y = top >> 6;
1751
1752 DPRINT("CX %d CY %d BBX %d BBY %d GOX %d GOY %d\n",
1753 gm.gmCellIncX, gm.gmCellIncY,
1754 gm.gmBlackBoxX, gm.gmBlackBoxY,
1755 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1756
1757 IntUnLockFreeType;
1758
1759 if (pgm) RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
1760
1761 if (iFormat == GGO_METRICS)
1762 {
1763 DPRINT("GGO_METRICS Exit!\n");
1764 return 1; /* FIXME */
1765 }
1766
1767 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
1768 {
1769 DPRINT1("loaded a bitmap\n");
1770 return GDI_ERROR;
1771 }
1772
1773 switch (iFormat)
1774 {
1775 case GGO_BITMAP:
1776 width = gm.gmBlackBoxX;
1777 height = gm.gmBlackBoxY;
1778 pitch = ((width + 31) >> 5) << 2;
1779 needed = pitch * height;
1780
1781 if (!pvBuf || !cjBuf) break;
1782
1783 switch (ft_face->glyph->format)
1784 {
1785 case ft_glyph_format_bitmap:
1786 {
1787 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
1788 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1789 INT h = ft_face->glyph->bitmap.rows;
1790 while (h--)
1791 {
1792 RtlCopyMemory(dst, src, w);
1793 src += ft_face->glyph->bitmap.pitch;
1794 dst += pitch;
1795 }
1796 break;
1797 }
1798
1799 case ft_glyph_format_outline:
1800 ft_bitmap.width = width;
1801 ft_bitmap.rows = height;
1802 ft_bitmap.pitch = pitch;
1803 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1804 ft_bitmap.buffer = pvBuf;
1805
1806 IntLockFreeType;
1807 if (needsTransform)
1808 {
1809 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1810 }
1811 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1812 /* Note: FreeType will only set 'black' bits for us. */
1813 RtlZeroMemory(pvBuf, needed);
1814 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1815 IntUnLockFreeType;
1816 break;
1817
1818 default:
1819 DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
1820 return GDI_ERROR;
1821 }
1822 break;
1823
1824 case GGO_GRAY2_BITMAP:
1825 case GGO_GRAY4_BITMAP:
1826 case GGO_GRAY8_BITMAP:
1827 {
1828 unsigned int mult, row, col;
1829 BYTE *start, *ptr;
1830
1831 width = gm.gmBlackBoxX;
1832 height = gm.gmBlackBoxY;
1833 pitch = (width + 3) / 4 * 4;
1834 needed = pitch * height;
1835
1836 if (!pvBuf || !cjBuf) break;
1837
1838 switch (ft_face->glyph->format)
1839 {
1840 case ft_glyph_format_bitmap:
1841 {
1842 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
1843 INT h = ft_face->glyph->bitmap.rows;
1844 INT x;
1845 while (h--)
1846 {
1847 for (x = 0; x < pitch; x++)
1848 {
1849 if (x < ft_face->glyph->bitmap.width)
1850 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
1851 else
1852 dst[x] = 0;
1853 }
1854 src += ft_face->glyph->bitmap.pitch;
1855 dst += pitch;
1856 }
1857 return needed;
1858 }
1859 case ft_glyph_format_outline:
1860 {
1861 ft_bitmap.width = width;
1862 ft_bitmap.rows = height;
1863 ft_bitmap.pitch = pitch;
1864 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1865 ft_bitmap.buffer = pvBuf;
1866
1867 IntLockFreeType;
1868 if (needsTransform)
1869 {
1870 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1871 }
1872 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1873 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
1874 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1875 IntUnLockFreeType;
1876
1877 if (iFormat == GGO_GRAY2_BITMAP)
1878 mult = 4;
1879 else if (iFormat == GGO_GRAY4_BITMAP)
1880 mult = 16;
1881 else if (iFormat == GGO_GRAY8_BITMAP)
1882 mult = 64;
1883 else
1884 {
1885 return GDI_ERROR;
1886 }
1887 }
1888 default:
1889 DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
1890 return GDI_ERROR;
1891 }
1892 start = pvBuf;
1893 for (row = 0; row < height; row++)
1894 {
1895 ptr = start;
1896 for (col = 0; col < width; col++, ptr++)
1897 {
1898 *ptr = (((int)*ptr) * mult + 128) / 256;
1899 }
1900 start += pitch;
1901 }
1902 break;
1903 }
1904
1905 case GGO_NATIVE:
1906 {
1907 int contour, point = 0, first_pt;
1908 FT_Outline *outline = &ft_face->glyph->outline;
1909 TTPOLYGONHEADER *pph;
1910 TTPOLYCURVE *ppc;
1911 DWORD pph_start, cpfx, type;
1912
1913 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
1914
1915 IntLockFreeType;
1916 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
1917
1918 for (contour = 0; contour < outline->n_contours; contour++)
1919 {
1920 pph_start = needed;
1921 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
1922 first_pt = point;
1923 if (pvBuf)
1924 {
1925 pph->dwType = TT_POLYGON_TYPE;
1926 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1927 }
1928 needed += sizeof(*pph);
1929 point++;
1930 while (point <= outline->contours[contour])
1931 {
1932 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
1933 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1934 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1935 cpfx = 0;
1936 do
1937 {
1938 if (pvBuf)
1939 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1940 cpfx++;
1941 point++;
1942 }
1943 while (point <= outline->contours[contour] &&
1944 (outline->tags[point] & FT_Curve_Tag_On) ==
1945 (outline->tags[point-1] & FT_Curve_Tag_On));
1946
1947 /* At the end of a contour Windows adds the start point, but
1948 only for Beziers */
1949 if (point > outline->contours[contour] &&
1950 !(outline->tags[point-1] & FT_Curve_Tag_On))
1951 {
1952 if (pvBuf)
1953 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1954 cpfx++;
1955 }
1956 else if (point <= outline->contours[contour] &&
1957 outline->tags[point] & FT_Curve_Tag_On)
1958 {
1959 /* add closing pt for bezier */
1960 if (pvBuf)
1961 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1962 cpfx++;
1963 point++;
1964 }
1965 if (pvBuf)
1966 {
1967 ppc->wType = type;
1968 ppc->cpfx = cpfx;
1969 }
1970 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1971 }
1972 if (pvBuf) pph->cb = needed - pph_start;
1973 }
1974 IntUnLockFreeType;
1975 break;
1976 }
1977 case GGO_BEZIER:
1978 {
1979 /* Convert the quadratic Beziers to cubic Beziers.
1980 The parametric eqn for a cubic Bezier is, from PLRM:
1981 r(t) = at^3 + bt^2 + ct + r0
1982 with the control points:
1983 r1 = r0 + c/3
1984 r2 = r1 + (c + b)/3
1985 r3 = r0 + c + b + a
1986
1987 A quadratic Beizer has the form:
1988 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1989
1990 So equating powers of t leads to:
1991 r1 = 2/3 p1 + 1/3 p0
1992 r2 = 2/3 p1 + 1/3 p2
1993 and of course r0 = p0, r3 = p2
1994 */
1995
1996 int contour, point = 0, first_pt;
1997 FT_Outline *outline = &ft_face->glyph->outline;
1998 TTPOLYGONHEADER *pph;
1999 TTPOLYCURVE *ppc;
2000 DWORD pph_start, cpfx, type;
2001 FT_Vector cubic_control[4];
2002 if (cjBuf == 0) pvBuf = NULL;
2003
2004 if (needsTransform && pvBuf)
2005 {
2006 IntLockFreeType;
2007 FT_Outline_Transform(outline, &transMat);
2008 IntUnLockFreeType;
2009 }
2010
2011 for (contour = 0; contour < outline->n_contours; contour++)
2012 {
2013 pph_start = needed;
2014 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
2015 first_pt = point;
2016 if (pvBuf)
2017 {
2018 pph->dwType = TT_POLYGON_TYPE;
2019 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2020 }
2021 needed += sizeof(*pph);
2022 point++;
2023 while (point <= outline->contours[contour])
2024 {
2025 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
2026 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2027 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2028 cpfx = 0;
2029 do
2030 {
2031 if (type == TT_PRIM_LINE)
2032 {
2033 if (pvBuf)
2034 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2035 cpfx++;
2036 point++;
2037 }
2038 else
2039 {
2040 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2041 so cpfx = 3n */
2042
2043 /* FIXME: Possible optimization in endpoint calculation
2044 if there are two consecutive curves */
2045 cubic_control[0] = outline->points[point-1];
2046 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2047 {
2048 cubic_control[0].x += outline->points[point].x + 1;
2049 cubic_control[0].y += outline->points[point].y + 1;
2050 cubic_control[0].x >>= 1;
2051 cubic_control[0].y >>= 1;
2052 }
2053 if (point+1 > outline->contours[contour])
2054 cubic_control[3] = outline->points[first_pt];
2055 else
2056 {
2057 cubic_control[3] = outline->points[point+1];
2058 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2059 {
2060 cubic_control[3].x += outline->points[point].x + 1;
2061 cubic_control[3].y += outline->points[point].y + 1;
2062 cubic_control[3].x >>= 1;
2063 cubic_control[3].y >>= 1;
2064 }
2065 }
2066 /* r1 = 1/3 p0 + 2/3 p1
2067 r2 = 1/3 p2 + 2/3 p1 */
2068 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2069 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2070 cubic_control[2] = cubic_control[1];
2071 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2072 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2073 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2074 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2075 if (pvBuf)
2076 {
2077 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2078 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2079 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2080 }
2081 cpfx += 3;
2082 point++;
2083 }
2084 }
2085 while (point <= outline->contours[contour] &&
2086 (outline->tags[point] & FT_Curve_Tag_On) ==
2087 (outline->tags[point-1] & FT_Curve_Tag_On));
2088 /* At the end of a contour Windows adds the start point,
2089 but only for Beziers and we've already done that.
2090 */
2091 if (point <= outline->contours[contour] &&
2092 outline->tags[point] & FT_Curve_Tag_On)
2093 {
2094 /* This is the closing pt of a bezier, but we've already
2095 added it, so just inc point and carry on */
2096 point++;
2097 }
2098 if (pvBuf)
2099 {
2100 ppc->wType = type;
2101 ppc->cpfx = cpfx;
2102 }
2103 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2104 }
2105 if (pvBuf) pph->cb = needed - pph_start;
2106 }
2107 break;
2108 }
2109
2110 default:
2111 DPRINT1("Unsupported format %d\n", iFormat);
2112 return GDI_ERROR;
2113 }
2114
2115 DPRINT("ftGdiGetGlyphOutline END and needed %d\n", needed);
2116 return needed;
2117 }
2118
2119 BOOL
2120 FASTCALL
2121 TextIntGetTextExtentPoint(PDC dc,
2122 PTEXTOBJ TextObj,
2123 LPCWSTR String,
2124 INT Count,
2125 ULONG MaxExtent,
2126 LPINT Fit,
2127 LPINT Dx,
2128 LPSIZE Size,
2129 FLONG fl)
2130 {
2131 PFONTGDI FontGDI;
2132 FT_Face face;
2133 FT_GlyphSlot glyph;
2134 FT_BitmapGlyph realglyph;
2135 INT error, n, glyph_index, i, previous;
2136 ULONGLONG TotalWidth = 0;
2137 FT_CharMap charmap, found = NULL;
2138 BOOL use_kerning;
2139 FT_Render_Mode RenderMode;
2140 BOOLEAN Render;
2141
2142 FontGDI = ObjToGDI(TextObj->Font, FONT);
2143
2144 face = FontGDI->face;
2145 if (NULL != Fit)
2146 {
2147 *Fit = 0;
2148 }
2149
2150 IntLockFreeType;
2151 if (face->charmap == NULL)
2152 {
2153 DPRINT("WARNING: No charmap selected!\n");
2154 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2155
2156 for (n = 0; n < face->num_charmaps; n++)
2157 {
2158 charmap = face->charmaps[n];
2159 DPRINT("found charmap encoding: %u\n", charmap->encoding);
2160 if (charmap->encoding != 0)
2161 {
2162 found = charmap;
2163 break;
2164 }
2165 }
2166
2167 if (! found)
2168 {
2169 DPRINT1("WARNING: Could not find desired charmap!\n");
2170 }
2171
2172 error = FT_Set_Charmap(face, found);
2173 if (error)
2174 {
2175 DPRINT1("WARNING: Could not set the charmap!\n");
2176 }
2177 }
2178
2179 Render = IntIsFontRenderingEnabled();
2180 if (Render)
2181 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
2182 else
2183 RenderMode = FT_RENDER_MODE_MONO;
2184
2185 error = FT_Set_Pixel_Sizes(face,
2186 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
2187 /* FIXME should set character height if neg */
2188 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
2189 - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
2190 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
2191 if (error)
2192 {
2193 DPRINT1("Error in setting pixel sizes: %u\n", error);
2194 }
2195
2196 use_kerning = FT_HAS_KERNING(face);
2197 previous = 0;
2198
2199 for (i = 0; i < Count; i++)
2200 {
2201 if (fl & GTEF_INDICES)
2202 glyph_index = *String;
2203 else
2204 glyph_index = FT_Get_Char_Index(face, *String);
2205
2206 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
2207 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
2208 {
2209 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2210 if (error)
2211 {
2212 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
2213 break;
2214 }
2215
2216 glyph = face->glyph;
2217 realglyph = ftGdiGlyphCacheSet(face, glyph_index,
2218 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
2219 if (!realglyph)
2220 {
2221 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
2222 break;
2223 }
2224 }
2225
2226 /* retrieve kerning distance */
2227 if (use_kerning && previous && glyph_index)
2228 {
2229 FT_Vector delta;
2230 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
2231 TotalWidth += delta.x;
2232 }
2233
2234 TotalWidth += realglyph->root.advance.x >> 10;
2235
2236 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
2237 {
2238 *Fit = i + 1;
2239 }
2240 if (NULL != Dx)
2241 {
2242 Dx[i] = (TotalWidth + 32) >> 6;
2243 }
2244
2245 previous = glyph_index;
2246 String++;
2247 }
2248 IntUnLockFreeType;
2249
2250 Size->cx = (TotalWidth + 32) >> 6;
2251 Size->cy = (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight);
2252 Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
2253
2254 return TRUE;
2255 }
2256
2257
2258 INT
2259 FASTCALL
2260 ftGdiGetTextCharsetInfo(
2261 PDC Dc,
2262 LPFONTSIGNATURE lpSig,
2263 DWORD dwFlags)
2264 {
2265 PDC_ATTR pdcattr;
2266 UINT Ret = DEFAULT_CHARSET, i;
2267 HFONT hFont;
2268 PTEXTOBJ TextObj;
2269 PFONTGDI FontGdi;
2270 FONTSIGNATURE fs;
2271 TT_OS2 *pOS2;
2272 FT_Face Face;
2273 CHARSETINFO csi;
2274 DWORD cp, fs0;
2275 USHORT usACP, usOEM;
2276
2277 pdcattr = Dc->pdcattr;
2278 hFont = pdcattr->hlfntNew;
2279 TextObj = RealizeFontInit(hFont);
2280
2281 if (!TextObj)
2282 {
2283 SetLastWin32Error(ERROR_INVALID_HANDLE);
2284 return Ret;
2285 }
2286 FontGdi = ObjToGDI(TextObj->Font, FONT);
2287 Face = FontGdi->face;
2288 TEXTOBJ_UnlockText(TextObj);
2289
2290 IntLockFreeType;
2291 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2292 IntUnLockFreeType;
2293 memset(&fs, 0, sizeof(FONTSIGNATURE));
2294 if (NULL != pOS2)
2295 {
2296 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2297 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2298 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2299 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2300 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2301 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2302 if (pOS2->version == 0)
2303 {
2304 FT_UInt dummy;
2305
2306 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
2307 fs.fsCsb[0] |= FS_LATIN1;
2308 else
2309 fs.fsCsb[0] |= FS_SYMBOL;
2310 }
2311 }
2312 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
2313 if (fs.fsCsb[0] == 0)
2314 { /* let's see if we can find any interesting cmaps */
2315 for (i = 0; i < Face->num_charmaps; i++)
2316 {
2317 switch (Face->charmaps[i]->encoding)
2318 {
2319 case FT_ENCODING_UNICODE:
2320 case FT_ENCODING_APPLE_ROMAN:
2321 fs.fsCsb[0] |= FS_LATIN1;
2322 break;
2323 case FT_ENCODING_MS_SYMBOL:
2324 fs.fsCsb[0] |= FS_SYMBOL;
2325 break;
2326 default:
2327 break;
2328 }
2329 }
2330 }
2331 if (lpSig)
2332 {
2333 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
2334 }
2335
2336 RtlGetDefaultCodePage(&usACP, &usOEM);
2337 cp = usACP;
2338
2339 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
2340 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
2341 {
2342 DPRINT("Hit 1\n");
2343 Ret = csi.ciCharset;
2344 goto Exit;
2345 }
2346
2347 for (i = 0; i < MAXTCIINDEX; i++)
2348 {
2349 fs0 = 1L << i;
2350 if (fs.fsCsb[0] & fs0)
2351 {
2352 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
2353 {
2354 //*cp = csi.ciACP;
2355 DPRINT("Hit 2\n");
2356 Ret = csi.ciCharset;
2357 goto Exit;
2358 }
2359 else
2360 DPRINT1("TCI failing on %x\n", fs0);
2361 }
2362 }
2363 Exit:
2364 DPRINT("CharSet %d CodePage %d\n",csi.ciCharset, csi.ciACP);
2365 return (MAKELONG(csi.ciACP, csi.ciCharset));
2366 }
2367
2368
2369 DWORD
2370 FASTCALL
2371 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
2372 {
2373 DWORD size = 0;
2374 DWORD num_ranges = 0;
2375 FT_Face face = Font->face;
2376
2377 if (face->charmap->encoding == FT_ENCODING_UNICODE)
2378 {
2379 FT_UInt glyph_code = 0;
2380 FT_ULong char_code, char_code_prev;
2381
2382 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
2383
2384 DPRINT("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
2385 face->num_glyphs, glyph_code, char_code);
2386
2387 if (!glyph_code) return 0;
2388
2389 if (glyphset)
2390 {
2391 glyphset->ranges[0].wcLow = (USHORT)char_code;
2392 glyphset->ranges[0].cGlyphs = 0;
2393 glyphset->cGlyphsSupported = 0;
2394 }
2395
2396 num_ranges = 1;
2397 while (glyph_code)
2398 {
2399 if (char_code < char_code_prev)
2400 {
2401 DPRINT1("expected increasing char code from FT_Get_Next_Char\n");
2402 return 0;
2403 }
2404 if (char_code - char_code_prev > 1)
2405 {
2406 num_ranges++;
2407 if (glyphset)
2408 {
2409 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
2410 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
2411 glyphset->cGlyphsSupported++;
2412 }
2413 }
2414 else if (glyphset)
2415 {
2416 glyphset->ranges[num_ranges - 1].cGlyphs++;
2417 glyphset->cGlyphsSupported++;
2418 }
2419 char_code_prev = char_code;
2420 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
2421 }
2422 }
2423 else
2424 DPRINT1("encoding %u not supported\n", face->charmap->encoding);
2425
2426 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
2427 if (glyphset)
2428 {
2429 glyphset->cbThis = size;
2430 glyphset->cRanges = num_ranges;
2431 }
2432 return size;
2433 }
2434
2435
2436 BOOL
2437 FASTCALL
2438 ftGdiGetTextMetricsW(
2439 HDC hDC,
2440 PTMW_INTERNAL ptmwi)
2441 {
2442 PDC dc;
2443 PDC_ATTR pdcattr;
2444 PTEXTOBJ TextObj;
2445 PFONTGDI FontGDI;
2446 FT_Face Face;
2447 TT_OS2 *pOS2;
2448 TT_HoriHeader *pHori;
2449 FT_WinFNT_HeaderRec Win;
2450 ULONG Error;
2451 NTSTATUS Status = STATUS_SUCCESS;
2452
2453 if (!ptmwi)
2454 {
2455 SetLastWin32Error(STATUS_INVALID_PARAMETER);
2456 return FALSE;
2457 }
2458
2459 if (!(dc = DC_LockDc(hDC)))
2460 {
2461 SetLastWin32Error(ERROR_INVALID_HANDLE);
2462 return FALSE;
2463 }
2464 pdcattr = dc->pdcattr;
2465 TextObj = RealizeFontInit(pdcattr->hlfntNew);
2466 if (NULL != TextObj)
2467 {
2468 FontGDI = ObjToGDI(TextObj->Font, FONT);
2469
2470 Face = FontGDI->face;
2471 IntLockFreeType;
2472 Error = FT_Set_Pixel_Sizes(Face,
2473 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
2474 /* FIXME should set character height if neg */
2475 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
2476 - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
2477 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
2478 IntUnLockFreeType;
2479 if (0 != Error)
2480 {
2481 DPRINT1("Error in setting pixel sizes: %u\n", Error);
2482 Status = STATUS_UNSUCCESSFUL;
2483 }
2484 else
2485 {
2486 Status = STATUS_SUCCESS;
2487
2488 IntLockFreeType;
2489 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
2490 if (NULL == pOS2)
2491 {
2492 DPRINT1("Can't find OS/2 table - not TT font?\n");
2493 Status = STATUS_INTERNAL_ERROR;
2494 }
2495
2496 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
2497 if (NULL == pHori)
2498 {
2499 DPRINT1("Can't find HHEA table - not TT font?\n");
2500 Status = STATUS_INTERNAL_ERROR;
2501 }
2502
2503 Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
2504
2505 IntUnLockFreeType;
2506
2507 if (NT_SUCCESS(Status))
2508 {
2509 if (!(FontGDI->flRealizedType & FDM_TYPE_TEXT_METRIC))
2510 {
2511 FillTM(&FontGDI->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
2512 FontGDI->flRealizedType |= FDM_TYPE_TEXT_METRIC;
2513 }
2514
2515 RtlCopyMemory(&ptmwi->TextMetric, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
2516 /* FIXME: Fill Diff member */
2517 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
2518 }
2519 }
2520 TEXTOBJ_UnlockText(TextObj);
2521 }
2522 else
2523 {
2524 Status = STATUS_INVALID_HANDLE;
2525 }
2526 DC_UnlockDc(dc);
2527
2528 if (!NT_SUCCESS(Status))
2529 {
2530 SetLastNtError(Status);
2531 return FALSE;
2532 }
2533 return TRUE;
2534 }
2535
2536
2537 DWORD
2538 FASTCALL
2539 ftGdiGetFontData(
2540 PFONTGDI FontGdi,
2541 DWORD Table,
2542 DWORD Offset,
2543 PVOID Buffer,
2544 DWORD Size)
2545 {
2546 DWORD Result = GDI_ERROR;
2547
2548 IntLockFreeType;
2549
2550 if (FT_IS_SFNT(FontGdi->face))
2551 {
2552 if (Table)
2553 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
2554 (Table << 8 & 0xFF0000);
2555
2556 if (!Buffer) Size = 0;
2557
2558 if (Buffer && Size)
2559 {
2560 FT_Error Error;
2561 FT_ULong Needed = 0;
2562
2563 Error = FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, NULL, &Needed);
2564
2565 if ( !Error && Needed < Size) Size = Needed;
2566 }
2567 if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
2568 Result = Size;
2569 }
2570
2571 IntUnLockFreeType;
2572
2573 return Result;
2574 }
2575
2576 static UINT FASTCALL
2577 GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
2578 {
2579 ANSI_STRING EntryFaceNameA;
2580 UNICODE_STRING EntryFaceNameW;
2581 unsigned Size;
2582 OUTLINETEXTMETRICW *Otm;
2583 LONG WeightDiff;
2584 NTSTATUS Status;
2585 UINT Score = 1;
2586
2587 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
2588 Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2589 if (NT_SUCCESS(Status))
2590 {
2591 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2592 {
2593 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2594 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2595 }
2596 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
2597 {
2598 Score += 49;
2599 }
2600 RtlFreeUnicodeString(&EntryFaceNameW);
2601 }
2602
2603 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2604 Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
2605 if (NULL == Otm)
2606 {
2607 return Score;
2608 }
2609 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2610
2611 if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
2612 (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
2613 {
2614 Score += 25;
2615 }
2616 if (LogFont->lfWeight != FW_DONTCARE)
2617 {
2618 if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
2619 {
2620 WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
2621 }
2622 else
2623 {
2624 WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
2625 }
2626 Score += (1000 - WeightDiff) / (1000 / 25);
2627 }
2628 else
2629 {
2630 Score += 25;
2631 }
2632
2633 ExFreePool(Otm);
2634
2635 return Score;
2636 }
2637
2638 static __inline VOID
2639 FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
2640 PUNICODE_STRING FaceName, PLIST_ENTRY Head)
2641 {
2642 PLIST_ENTRY Entry;
2643 PFONT_ENTRY CurrentEntry;
2644 FONTGDI *FontGDI;
2645 UINT Score;
2646
2647 Entry = Head->Flink;
2648 while (Entry != Head)
2649 {
2650 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2651
2652 FontGDI = CurrentEntry->Font;
2653 ASSERT(FontGDI);
2654
2655 Score = GetFontScore(LogFont, FaceName, FontGDI);
2656 if (*MatchScore == 0 || *MatchScore < Score)
2657 {
2658 *FontObj = GDIToObj(FontGDI, FONT);
2659 *MatchScore = Score;
2660 }
2661 Entry = Entry->Flink;
2662 }
2663 }
2664
2665 static __inline BOOLEAN
2666 SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
2667 LPCWSTR Key)
2668 {
2669 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2670 NTSTATUS Status;
2671 UNICODE_STRING Value;
2672
2673 RtlInitUnicodeString(&Value, NULL);
2674
2675 QueryTable[0].QueryRoutine = NULL;
2676 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
2677 RTL_QUERY_REGISTRY_REQUIRED;
2678 QueryTable[0].Name = FaceName->Buffer;
2679 QueryTable[0].EntryContext = &Value;
2680 QueryTable[0].DefaultType = REG_NONE;
2681 QueryTable[0].DefaultData = NULL;
2682 QueryTable[0].DefaultLength = 0;
2683
2684 QueryTable[1].QueryRoutine = NULL;
2685 QueryTable[1].Name = NULL;
2686
2687 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2688 Key,
2689 QueryTable,
2690 NULL,
2691 NULL);
2692 if (NT_SUCCESS(Status))
2693 {
2694 RtlFreeUnicodeString(FaceName);
2695 *FaceName = Value;
2696 }
2697
2698 return NT_SUCCESS(Status);
2699 }
2700
2701 static __inline void
2702 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
2703 {
2704 if (10 < Level) /* Enough is enough */
2705 {
2706 return;
2707 }
2708
2709 if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
2710 SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
2711 {
2712 SubstituteFontFamily(FaceName, Level + 1);
2713 }
2714 }
2715
2716 static
2717 VOID
2718 FASTCALL
2719 IntFontType(PFONTGDI Font)
2720 {
2721 PS_FontInfoRec psfInfo;
2722 FT_ULong tmp_size = 0;
2723
2724 if (FT_HAS_MULTIPLE_MASTERS(Font->face))
2725 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
2726 if (FT_HAS_VERTICAL( Font->face ))
2727 Font->FontObj.flFontType |= FO_VERT_FACE;
2728 if (FT_IS_SCALABLE( Font->face ))
2729 Font->FontObj.flFontType |= FO_TYPE_RASTER;
2730 if (FT_IS_SFNT(Font->face))
2731 {
2732 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
2733 if (FT_Get_Sfnt_Table(Font->face, ft_sfnt_post))
2734 Font->FontObj.flFontType |= FO_POSTSCRIPT;
2735 }
2736 if (!FT_Get_PS_Font_Info(Font->face, &psfInfo ))
2737 {
2738 Font->FontObj.flFontType |= FO_POSTSCRIPT;
2739 }
2740 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
2741 if (!FT_Load_Sfnt_Table(Font->face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
2742 {
2743 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
2744 }
2745 }
2746
2747 NTSTATUS
2748 FASTCALL
2749 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
2750 {
2751 NTSTATUS Status = STATUS_SUCCESS;
2752 PTEXTOBJ TextObj;
2753 UNICODE_STRING FaceName;
2754 PPROCESSINFO Win32Process;
2755 UINT MatchScore;
2756
2757 if (!pTextObj)
2758 {
2759 TextObj = TEXTOBJ_LockText(FontHandle);
2760 if (NULL == TextObj)
2761 {
2762 return STATUS_INVALID_HANDLE;
2763 }
2764
2765 if (TextObj->fl & TEXTOBJECT_INIT)
2766 {
2767 TEXTOBJ_UnlockText(TextObj);
2768 return STATUS_SUCCESS;
2769 }
2770 }
2771 else
2772 TextObj = pTextObj;
2773
2774 if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName))
2775 {
2776 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
2777 return STATUS_NO_MEMORY;
2778 }
2779 SubstituteFontFamily(&FaceName, 0);
2780 MatchScore = 0;
2781 TextObj->Font = NULL;
2782
2783 /* First search private fonts */
2784 Win32Process = PsGetCurrentProcessWin32Process();
2785 IntLockProcessPrivateFonts(Win32Process);
2786 FindBestFontFromList(&TextObj->Font, &MatchScore,
2787 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
2788 &Win32Process->PrivateFontListHead);
2789 IntUnLockProcessPrivateFonts(Win32Process);
2790
2791 /* Search system fonts */
2792 IntLockGlobalFonts;
2793 FindBestFontFromList(&TextObj->Font, &MatchScore,
2794 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
2795 &FontListHead);
2796 IntUnLockGlobalFonts;
2797 if (NULL == TextObj->Font)
2798 {
2799 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
2800 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName);
2801 Status = STATUS_NOT_FOUND;
2802 }
2803 else
2804 {
2805 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
2806 // Need hdev, when freetype is loaded need to create DEVOBJ for
2807 // Consumer and Producer.
2808 TextObj->Font->iUniq = 1; // Now it can be cached.
2809 IntFontType(FontGdi);
2810 FontGdi->flType = TextObj->Font->flFontType;
2811 FontGdi->flRealizedType = 0;
2812 FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0;
2813 FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0;
2814 TextObj->fl |= TEXTOBJECT_INIT;
2815 Status = STATUS_SUCCESS;
2816 }
2817
2818 RtlFreeUnicodeString(&FaceName);
2819 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
2820
2821 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
2822
2823 return Status;
2824 }
2825
2826
2827 static
2828 BOOL
2829 FASTCALL
2830 IntGetFullFileName(
2831 POBJECT_NAME_INFORMATION NameInfo,
2832 ULONG Size,
2833 PUNICODE_STRING FileName)
2834 {
2835 NTSTATUS Status;
2836 OBJECT_ATTRIBUTES ObjectAttributes;
2837 HANDLE hFile;
2838 IO_STATUS_BLOCK IoStatusBlock;
2839 ULONG Desired;
2840
2841 InitializeObjectAttributes(&ObjectAttributes,
2842 FileName,
2843 OBJ_CASE_INSENSITIVE,
2844 NULL,
2845 NULL);
2846
2847 Status = ZwOpenFile(
2848 &hFile,
2849 0, //FILE_READ_ATTRIBUTES,
2850 &ObjectAttributes,
2851 &IoStatusBlock,
2852 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2853 0);
2854
2855 if (!NT_SUCCESS(Status))
2856 {
2857 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
2858 return FALSE;
2859 }
2860
2861 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
2862 ZwClose(hFile);
2863 if (!NT_SUCCESS(Status))
2864 {
2865 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
2866 return FALSE;
2867 }
2868
2869 return TRUE;
2870 }
2871
2872 BOOL
2873 FASTCALL
2874 IntGdiGetFontResourceInfo(
2875 PUNICODE_STRING FileName,
2876 PVOID pBuffer,
2877 DWORD *pdwBytes,
2878 DWORD dwType)
2879 {
2880 UNICODE_STRING EntryFileName;
2881 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
2882 PLIST_ENTRY ListEntry;
2883 PFONT_ENTRY FontEntry;
2884 FONTFAMILYINFO Info;
2885 ULONG Size;
2886 BOOL bFound = FALSE;
2887
2888 /* Create buffer for full path name */
2889 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
2890 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
2891 if (!NameInfo1)
2892 {
2893 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2894 return FALSE;
2895 }
2896
2897 /* Get the full path name */
2898 if (!IntGetFullFileName(NameInfo1, Size, FileName))
2899 {
2900 ExFreePool(NameInfo1);
2901 return FALSE;
2902 }
2903
2904 /* Create a buffer for the entries' names */
2905 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
2906 if (!NameInfo2)
2907 {
2908 ExFreePool(NameInfo1);
2909 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2910 return FALSE;
2911 }
2912
2913 /* Try to find the pathname in the global font list */
2914 IntLockGlobalFonts;
2915 for (ListEntry = FontListHead.Flink;
2916 ListEntry != &FontListHead;
2917 ListEntry = ListEntry->Flink)
2918 {
2919 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
2920 if (FontEntry->Font->Filename != NULL)
2921 {
2922 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
2923 if (IntGetFullFileName(NameInfo2, Size, &EntryFileName))
2924 {
2925 if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
2926 {
2927 /* found */
2928 FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font);
2929 bFound = TRUE;
2930 break;
2931 }
2932 }
2933 }
2934 }
2935 IntUnLockGlobalFonts;
2936
2937 /* Free the buffers */
2938 ExFreePool(NameInfo1);
2939 ExFreePool(NameInfo2);
2940
2941 if (!bFound && dwType != 5)
2942 {
2943 /* Font could not be found in system table
2944 dwType == 5 will still handle this */
2945 return FALSE;
2946 }
2947
2948 switch (dwType)
2949 {
2950 case 0: /* FIXME: returns 1 or 2, don't know what this is atm */
2951 *(DWORD*)pBuffer = 1;
2952 *pdwBytes = sizeof(DWORD);
2953 break;
2954
2955 case 1: /* Copy the full font name */
2956 Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1;
2957 Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR);
2958 RtlCopyMemory(pBuffer, Info.EnumLogFontEx.elfFullName, Size);
2959 // FIXME: Do we have to zeroterminate?
2960 *pdwBytes = Size;
2961 break;
2962
2963 case 2: /* Copy a LOGFONTW structure */
2964 Info.EnumLogFontEx.elfLogFont.lfWidth = 0;
2965 RtlCopyMemory(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
2966 *pdwBytes = sizeof(LOGFONTW);
2967 break;
2968
2969 case 3: /* FIXME: What exactly is copied here? */
2970 *(DWORD*)pBuffer = 1;
2971 *pdwBytes = sizeof(DWORD*);