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