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