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