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