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