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