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