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