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