* Sync up to trunk head (r64829).
[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 < 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 unsigned 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; 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 return needed;
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 default:
2118 DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
2119 return GDI_ERROR;
2120 }
2121 start = pvBuf;
2122 for (row = 0; row < height; row++)
2123 {
2124 ptr = start;
2125 for (col = 0; col < width; col++, ptr++)
2126 {
2127 *ptr = (((int)*ptr) * mult + 128) / 256;
2128 }
2129 start += pitch;
2130 }
2131 break;
2132 }
2133
2134 case GGO_NATIVE:
2135 {
2136 FT_Outline *outline = &ft_face->glyph->outline;
2137
2138 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
2139
2140 IntLockFreeType;
2141 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
2142
2143 needed = get_native_glyph_outline(outline, cjBuf, NULL);
2144
2145 if (!pvBuf || !cjBuf)
2146 {
2147 IntUnLockFreeType;
2148 break;
2149 }
2150 if (needed > cjBuf)
2151 {
2152 IntUnLockFreeType;
2153 return GDI_ERROR;
2154 }
2155 get_native_glyph_outline(outline, cjBuf, pvBuf);
2156 IntUnLockFreeType;
2157 break;
2158 }
2159 case GGO_BEZIER:
2160 {
2161 FT_Outline *outline = &ft_face->glyph->outline;
2162 if (cjBuf == 0) pvBuf = NULL;
2163
2164 if (needsTransform && pvBuf)
2165 {
2166 IntLockFreeType;
2167 FT_Outline_Transform(outline, &transMat);
2168 IntUnLockFreeType;
2169 }
2170 needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
2171
2172 if (!pvBuf || !cjBuf)
2173 break;
2174 if (needed > cjBuf)
2175 return GDI_ERROR;
2176
2177 get_bezier_glyph_outline(outline, cjBuf, pvBuf);
2178 break;
2179 }
2180
2181 default:
2182 DPRINT1("Unsupported format %u\n", iFormat);
2183 return GDI_ERROR;
2184 }
2185
2186 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
2187 return needed;
2188 }
2189
2190 BOOL
2191 FASTCALL
2192 TextIntGetTextExtentPoint(PDC dc,
2193 PTEXTOBJ TextObj,
2194 LPCWSTR String,
2195 INT Count,
2196 ULONG MaxExtent,
2197 LPINT Fit,
2198 LPINT Dx,
2199 LPSIZE Size,
2200 FLONG fl)
2201 {
2202 PFONTGDI FontGDI;
2203 FT_Face face;
2204 FT_GlyphSlot glyph;
2205 FT_BitmapGlyph realglyph;
2206 INT error, n, glyph_index, i, previous;
2207 ULONGLONG TotalWidth = 0;
2208 FT_CharMap charmap, found = NULL;
2209 BOOL use_kerning;
2210 FT_Render_Mode RenderMode;
2211 BOOLEAN Render;
2212 PMATRIX pmxWorldToDevice;
2213
2214 FontGDI = ObjToGDI(TextObj->Font, FONT);
2215
2216 face = FontGDI->face;
2217 if (NULL != Fit)
2218 {
2219 *Fit = 0;
2220 }
2221
2222 IntLockFreeType;
2223 if (face->charmap == NULL)
2224 {
2225 DPRINT("WARNING: No charmap selected!\n");
2226 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2227
2228 for (n = 0; n < face->num_charmaps; n++)
2229 {
2230 charmap = face->charmaps[n];
2231 DPRINT("Found charmap encoding: %u\n", charmap->encoding);
2232 if (charmap->encoding != 0)
2233 {
2234 found = charmap;
2235 break;
2236 }
2237 }
2238
2239 if (! found)
2240 {
2241 DPRINT1("WARNING: Could not find desired charmap!\n");
2242 }
2243
2244 error = FT_Set_Charmap(face, found);
2245 if (error)
2246 {
2247 DPRINT1("WARNING: Could not set the charmap!\n");
2248 }
2249 }
2250
2251 Render = IntIsFontRenderingEnabled();
2252 if (Render)
2253 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
2254 else
2255 RenderMode = FT_RENDER_MODE_MONO;
2256
2257 error = FT_Set_Pixel_Sizes(face,
2258 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
2259 /* FIXME: Should set character height if neg */
2260 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
2261 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
2262 if (error)
2263 {
2264 DPRINT1("Error in setting pixel sizes: %d\n", error);
2265 }
2266
2267 /* Get the DC's world-to-device transformation matrix */
2268 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
2269 FtSetCoordinateTransform(face, pmxWorldToDevice);
2270
2271 use_kerning = FT_HAS_KERNING(face);
2272 previous = 0;
2273
2274 for (i = 0; i < Count; i++)
2275 {
2276 if (fl & GTEF_INDICES)
2277 glyph_index = *String;
2278 else
2279 glyph_index = FT_Get_Char_Index(face, *String);
2280
2281 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
2282 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
2283 pmxWorldToDevice)))
2284 {
2285 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2286 if (error)
2287 {
2288 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
2289 break;
2290 }
2291
2292 glyph = face->glyph;
2293 realglyph = ftGdiGlyphCacheSet(face,
2294 glyph_index,
2295 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
2296 pmxWorldToDevice,
2297 glyph,
2298 RenderMode);
2299 if (!realglyph)
2300 {
2301 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
2302 break;
2303 }
2304 }
2305
2306 /* Retrieve kerning distance */
2307 if (use_kerning && previous && glyph_index)
2308 {
2309 FT_Vector delta;
2310 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
2311 TotalWidth += delta.x;
2312 }
2313
2314 TotalWidth += realglyph->root.advance.x >> 10;
2315
2316 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
2317 {
2318 *Fit = i + 1;
2319 }
2320 if (NULL != Dx)
2321 {
2322 Dx[i] = (TotalWidth + 32) >> 6;
2323 }
2324
2325 previous = glyph_index;
2326 String++;
2327 }
2328 IntUnLockFreeType;
2329
2330 Size->cx = (TotalWidth + 32) >> 6;
2331 Size->cy = (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
2332 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
2333 Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
2334
2335 return TRUE;
2336 }
2337
2338
2339 INT
2340 FASTCALL
2341 ftGdiGetTextCharsetInfo(
2342 PDC Dc,
2343 LPFONTSIGNATURE lpSig,
2344 DWORD dwFlags)
2345 {
2346 PDC_ATTR pdcattr;
2347 UINT Ret = DEFAULT_CHARSET, i;
2348 HFONT hFont;
2349 PTEXTOBJ TextObj;
2350 PFONTGDI FontGdi;
2351 FONTSIGNATURE fs;
2352 TT_OS2 *pOS2;
2353 FT_Face Face;
2354 CHARSETINFO csi;
2355 DWORD cp, fs0;
2356 USHORT usACP, usOEM;
2357
2358 pdcattr = Dc->pdcattr;
2359 hFont = pdcattr->hlfntNew;
2360 TextObj = RealizeFontInit(hFont);
2361
2362 if (!TextObj)
2363 {
2364 EngSetLastError(ERROR_INVALID_HANDLE);
2365 return Ret;
2366 }
2367 FontGdi = ObjToGDI(TextObj->Font, FONT);
2368 Face = FontGdi->face;
2369 TEXTOBJ_UnlockText(TextObj);
2370
2371 IntLockFreeType;
2372 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2373 IntUnLockFreeType;
2374 memset(&fs, 0, sizeof(FONTSIGNATURE));
2375 if (NULL != pOS2)
2376 {
2377 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2378 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2379 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2380 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2381 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2382 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2383 if (pOS2->version == 0)
2384 {
2385 FT_UInt dummy;
2386
2387 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
2388 fs.fsCsb[0] |= FS_LATIN1;
2389 else
2390 fs.fsCsb[0] |= FS_SYMBOL;
2391 }
2392 }
2393 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
2394 if (fs.fsCsb[0] == 0)
2395 { /* Let's see if we can find any interesting cmaps */
2396 for (i = 0; i < Face->num_charmaps; i++)
2397 {
2398 switch (Face->charmaps[i]->encoding)
2399 {
2400 case FT_ENCODING_UNICODE:
2401 case FT_ENCODING_APPLE_ROMAN:
2402 fs.fsCsb[0] |= FS_LATIN1;
2403 break;
2404 case FT_ENCODING_MS_SYMBOL:
2405 fs.fsCsb[0] |= FS_SYMBOL;
2406 break;
2407 default:
2408 break;
2409 }
2410 }
2411 }
2412 if (lpSig)
2413 {
2414 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
2415 }
2416
2417 RtlGetDefaultCodePage(&usACP, &usOEM);
2418 cp = usACP;
2419
2420 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
2421 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
2422 {
2423 DPRINT("Hit 1\n");
2424 Ret = csi.ciCharset;
2425 goto Exit;
2426 }
2427
2428 for (i = 0; i < MAXTCIINDEX; i++)
2429 {
2430 fs0 = 1L << i;
2431 if (fs.fsCsb[0] & fs0)
2432 {
2433 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
2434 {
2435 // *cp = csi.ciACP;
2436 DPRINT("Hit 2\n");
2437 Ret = csi.ciCharset;
2438 goto Exit;
2439 }
2440 else
2441 DPRINT1("TCI failing on %x\n", fs0);
2442 }
2443 }
2444 Exit:
2445 DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
2446 return (MAKELONG(csi.ciACP, csi.ciCharset));
2447 }
2448
2449
2450 DWORD
2451 FASTCALL
2452 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
2453 {
2454 DWORD size = 0;
2455 DWORD num_ranges = 0;
2456 FT_Face face = Font->face;
2457
2458 if (face->charmap->encoding == FT_ENCODING_UNICODE)
2459 {
2460 FT_UInt glyph_code = 0;
2461 FT_ULong char_code, char_code_prev;
2462
2463 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
2464
2465 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
2466 face->num_glyphs, glyph_code, char_code);
2467
2468 if (!glyph_code) return 0;
2469
2470 if (glyphset)
2471 {
2472 glyphset->ranges[0].wcLow = (USHORT)char_code;
2473 glyphset->ranges[0].cGlyphs = 0;
2474 glyphset->cGlyphsSupported = 0;
2475 }
2476
2477 num_ranges = 1;
2478 while (glyph_code)
2479 {
2480 if (char_code < char_code_prev)
2481 {
2482 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
2483 return 0;
2484 }
2485 if (char_code - char_code_prev > 1)
2486 {
2487 num_ranges++;
2488 if (glyphset)
2489 {
2490 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
2491 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
2492 glyphset->cGlyphsSupported++;
2493 }
2494 }
2495 else if (glyphset)
2496 {
2497 glyphset->ranges[num_ranges - 1].cGlyphs++;
2498 glyphset->cGlyphsSupported++;
2499 }
2500 char_code_prev = char_code;
2501 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
2502 }
2503 }
2504 else
2505 DPRINT1("Encoding %u not supported\n", face->charmap->encoding);
2506
2507 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
2508 if (glyphset)
2509 {
2510 glyphset->cbThis = size;
2511 glyphset->cRanges = num_ranges;
2512 }
2513 return size;
2514 }
2515
2516
2517 BOOL
2518 FASTCALL
2519 ftGdiGetTextMetricsW(
2520 HDC hDC,
2521 PTMW_INTERNAL ptmwi)
2522 {
2523 PDC dc;
2524 PDC_ATTR pdcattr;
2525 PTEXTOBJ TextObj;
2526 PFONTGDI FontGDI;
2527 FT_Face Face;
2528 TT_OS2 *pOS2;
2529 TT_HoriHeader *pHori;
2530 FT_WinFNT_HeaderRec Win;
2531 ULONG Error;
2532 NTSTATUS Status = STATUS_SUCCESS;
2533
2534 if (!ptmwi)
2535 {
2536 EngSetLastError(STATUS_INVALID_PARAMETER);
2537 return FALSE;
2538 }
2539
2540 if (!(dc = DC_LockDc(hDC)))
2541 {
2542 EngSetLastError(ERROR_INVALID_HANDLE);
2543 return FALSE;
2544 }
2545 pdcattr = dc->pdcattr;
2546 TextObj = RealizeFontInit(pdcattr->hlfntNew);
2547 if (NULL != TextObj)
2548 {
2549 FontGDI = ObjToGDI(TextObj->Font, FONT);
2550
2551 Face = FontGDI->face;
2552 IntLockFreeType;
2553 Error = FT_Set_Pixel_Sizes(Face,
2554 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
2555 /* FIXME: Should set character height if neg */
2556 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
2557 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
2558 FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
2559 IntUnLockFreeType;
2560 if (0 != Error)
2561 {
2562 DPRINT1("Error in setting pixel sizes: %u\n", Error);
2563 Status = STATUS_UNSUCCESSFUL;
2564 }
2565 else
2566 {
2567 Status = STATUS_SUCCESS;
2568
2569 IntLockFreeType;
2570 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
2571 if (NULL == pOS2)
2572 {
2573 DPRINT1("Can't find OS/2 table - not TT font?\n");
2574 Status = STATUS_INTERNAL_ERROR;
2575 }
2576
2577 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
2578 if (NULL == pHori)
2579 {
2580 DPRINT1("Can't find HHEA table - not TT font?\n");
2581 Status = STATUS_INTERNAL_ERROR;
2582 }
2583
2584 Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
2585
2586 IntUnLockFreeType;
2587
2588 if (NT_SUCCESS(Status))
2589 {
2590 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
2591
2592 /* FIXME: Fill Diff member */
2593 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
2594 }
2595 }
2596 TEXTOBJ_UnlockText(TextObj);
2597 }
2598 else
2599 {
2600 Status = STATUS_INVALID_HANDLE;
2601 }
2602 DC_UnlockDc(dc);
2603
2604 if (!NT_SUCCESS(Status))
2605 {
2606 SetLastNtError(Status);
2607 return FALSE;
2608 }
2609 return TRUE;
2610 }
2611
2612
2613 DWORD
2614 FASTCALL
2615 ftGdiGetFontData(
2616 PFONTGDI FontGdi,
2617 DWORD Table,
2618 DWORD Offset,
2619 PVOID Buffer,
2620 DWORD Size)
2621 {
2622 DWORD Result = GDI_ERROR;
2623
2624 IntLockFreeType;
2625
2626 if (FT_IS_SFNT(FontGdi->face))
2627 {
2628 if (Table)
2629 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
2630 (Table << 8 & 0xFF0000);
2631
2632 if (!Buffer) Size = 0;
2633
2634 if (Buffer && Size)
2635 {
2636 FT_Error Error;
2637 FT_ULong Needed = 0;
2638
2639 Error = FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, NULL, &Needed);
2640
2641 if ( !Error && Needed < Size) Size = Needed;
2642 }
2643 if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
2644 Result = Size;
2645 }
2646
2647 IntUnLockFreeType;
2648
2649 return Result;
2650 }
2651
2652 static UINT FASTCALL
2653 GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
2654 {
2655 ANSI_STRING EntryFaceNameA;
2656 UNICODE_STRING EntryFaceNameW;
2657 unsigned Size;
2658 OUTLINETEXTMETRICW *Otm;
2659 LONG WeightDiff;
2660 NTSTATUS Status;
2661 UINT Score = 1;
2662
2663 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
2664 Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2665 if (NT_SUCCESS(Status))
2666 {
2667 static const UNICODE_STRING MarlettFaceNameW = RTL_CONSTANT_STRING(L"Marlett");
2668 static const UNICODE_STRING SymbolFaceNameW = RTL_CONSTANT_STRING(L"Symbol");
2669 static const UNICODE_STRING VGAFaceNameW = RTL_CONSTANT_STRING(L"VGA");
2670
2671 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2672 {
2673 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2674 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2675 }
2676
2677 if (!RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
2678 {
2679 Score += 49;
2680 }
2681
2682 /* FIXME: this is a work around to counter weird fonts on weird places.
2683 A proper fix would be to score fonts on more attributes than
2684 the ones in this function */
2685 if (!RtlCompareUnicodeString(&MarlettFaceNameW, &EntryFaceNameW, TRUE) &&
2686 RtlCompareUnicodeString(&MarlettFaceNameW, FaceName, TRUE))
2687 {
2688 Score = 0;
2689 }
2690
2691 if (!RtlCompareUnicodeString(&SymbolFaceNameW, &EntryFaceNameW, TRUE) &&
2692 RtlCompareUnicodeString(&SymbolFaceNameW, FaceName, TRUE))
2693 {
2694 Score = 0;
2695 }
2696
2697 if (!RtlCompareUnicodeString(&VGAFaceNameW, &EntryFaceNameW, TRUE) &&
2698 RtlCompareUnicodeString(&VGAFaceNameW, FaceName, TRUE))
2699 {
2700 Score = 0;
2701 }
2702
2703 RtlFreeUnicodeString(&EntryFaceNameW);
2704 }
2705
2706 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2707 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2708 if (NULL == Otm)
2709 {
2710 return Score;
2711 }
2712 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2713
2714 if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
2715 (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
2716 {
2717 Score += 25;
2718 }
2719 if (LogFont->lfWeight != FW_DONTCARE)
2720 {
2721 if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
2722 {
2723 WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
2724 }
2725 else
2726 {
2727 WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
2728 }
2729 Score += (1000 - WeightDiff) / (1000 / 25);
2730 }
2731 else
2732 {
2733 Score += 25;
2734 }
2735
2736 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2737
2738 return Score;
2739 }
2740
2741 static __inline VOID
2742 FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
2743 PUNICODE_STRING FaceName, PLIST_ENTRY Head)
2744 {
2745 PLIST_ENTRY Entry;
2746 PFONT_ENTRY CurrentEntry;
2747 FONTGDI *FontGDI;
2748 UINT Score;
2749 ASSERT(FontObj && MatchScore && LogFont && FaceName && Head);
2750 Entry = Head->Flink;
2751 while (Entry != Head)
2752 {
2753 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2754
2755 FontGDI = CurrentEntry->Font;
2756 ASSERT(FontGDI);
2757
2758 Score = GetFontScore(LogFont, FaceName, FontGDI);
2759 if (*MatchScore == 0 || *MatchScore < Score)
2760 {
2761 *FontObj = GDIToObj(FontGDI, FONT);
2762 *MatchScore = Score;
2763 }
2764 Entry = Entry->Flink;
2765 }
2766 }
2767
2768 static __inline BOOLEAN
2769 SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
2770 LPCWSTR Key)
2771 {
2772 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2773 NTSTATUS Status;
2774 UNICODE_STRING Value;
2775
2776 RtlInitUnicodeString(&Value, NULL);
2777
2778 QueryTable[0].QueryRoutine = NULL;
2779 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
2780 RTL_QUERY_REGISTRY_REQUIRED;
2781 QueryTable[0].Name = FaceName->Buffer;
2782 QueryTable[0].EntryContext = &Value;
2783 QueryTable[0].DefaultType = REG_NONE;
2784 QueryTable[0].DefaultData = NULL;
2785 QueryTable[0].DefaultLength = 0;
2786
2787 QueryTable[1].QueryRoutine = NULL;
2788 QueryTable[1].Name = NULL;
2789
2790 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2791 Key,
2792 QueryTable,
2793 NULL,
2794 NULL);
2795 if (NT_SUCCESS(Status))
2796 {
2797 RtlFreeUnicodeString(FaceName);
2798 *FaceName = Value;
2799 }
2800
2801 return NT_SUCCESS(Status);
2802 }
2803
2804 static __inline void
2805 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
2806 {
2807 if (10 < Level) /* Enough is enough */
2808 {
2809 return;
2810 }
2811
2812 if (SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
2813 {
2814 SubstituteFontFamily(FaceName, Level + 1);
2815 }
2816 }
2817
2818 static
2819 VOID
2820 FASTCALL
2821 IntFontType(PFONTGDI Font)
2822 {
2823 PS_FontInfoRec psfInfo;
2824 FT_ULong tmp_size = 0;
2825
2826 if (FT_HAS_MULTIPLE_MASTERS(Font->face))
2827 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
2828 if (FT_HAS_VERTICAL( Font->face ))
2829 Font->FontObj.flFontType |= FO_VERT_FACE;
2830 if (FT_IS_SCALABLE( Font->face ))
2831 Font->FontObj.flFontType |= FO_TYPE_RASTER;
2832 if (FT_IS_SFNT(Font->face))
2833 {
2834 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
2835 if (FT_Get_Sfnt_Table(Font->face, ft_sfnt_post))
2836 Font->FontObj.flFontType |= FO_POSTSCRIPT;
2837 }
2838 if (!FT_Get_PS_Font_Info(Font->face, &psfInfo ))
2839 {
2840 Font->FontObj.flFontType |= FO_POSTSCRIPT;
2841 }
2842 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
2843 if (!FT_Load_Sfnt_Table(Font->face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
2844 {
2845 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
2846 }
2847 }
2848
2849 NTSTATUS
2850 FASTCALL
2851 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
2852 {
2853 NTSTATUS Status = STATUS_SUCCESS;
2854 PTEXTOBJ TextObj;
2855 UNICODE_STRING FaceName;
2856 PPROCESSINFO Win32Process;
2857 UINT MatchScore;
2858
2859 if (!pTextObj)
2860 {
2861 TextObj = TEXTOBJ_LockText(FontHandle);
2862 if (NULL == TextObj)
2863 {
2864 return STATUS_INVALID_HANDLE;
2865 }
2866
2867 if (TextObj->fl & TEXTOBJECT_INIT)
2868 {
2869 TEXTOBJ_UnlockText(TextObj);
2870 return STATUS_SUCCESS;
2871 }
2872 }
2873 else
2874 TextObj = pTextObj;
2875
2876 if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName))
2877 {
2878 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
2879 return STATUS_NO_MEMORY;
2880 }
2881 SubstituteFontFamily(&FaceName, 0);
2882 MatchScore = 0;
2883 TextObj->Font = NULL;
2884
2885 /* First search private fonts */
2886 Win32Process = PsGetCurrentProcessWin32Process();
2887 IntLockProcessPrivateFonts(Win32Process);
2888 FindBestFontFromList(&TextObj->Font, &MatchScore,
2889 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
2890 &Win32Process->PrivateFontListHead);
2891 IntUnLockProcessPrivateFonts(Win32Process);
2892
2893 /* Search system fonts */
2894 IntLockGlobalFonts;
2895 FindBestFontFromList(&TextObj->Font, &MatchScore,
2896 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
2897 &FontListHead);
2898 IntUnLockGlobalFonts;
2899 if (NULL == TextObj->Font)
2900 {
2901 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
2902 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName);
2903 Status = STATUS_NOT_FOUND;
2904 }
2905 else
2906 {
2907 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
2908 // Need hdev, when freetype is loaded need to create DEVOBJ for
2909 // Consumer and Producer.
2910 TextObj->Font->iUniq = 1; // Now it can be cached.
2911 IntFontType(FontGdi);
2912 FontGdi->flType = TextObj->Font->flFontType;
2913 FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0;
2914 FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0;
2915 TextObj->fl |= TEXTOBJECT_INIT;
2916 Status = STATUS_SUCCESS;
2917 }
2918
2919 RtlFreeUnicodeString(&FaceName);
2920 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
2921
2922 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
2923
2924 return Status;
2925 }
2926
2927
2928 static
2929 BOOL
2930 FASTCALL
2931 IntGetFullFileName(
2932 POBJECT_NAME_INFORMATION NameInfo,
2933 ULONG Size,
2934 PUNICODE_STRING FileName)
2935 {
2936 NTSTATUS Status;
2937 OBJECT_ATTRIBUTES ObjectAttributes;
2938 HANDLE hFile;
2939 IO_STATUS_BLOCK IoStatusBlock;
2940 ULONG Desired;
2941
2942 InitializeObjectAttributes(&ObjectAttributes,
2943 FileName,
2944 OBJ_CASE_INSENSITIVE,
2945 NULL,
2946 NULL);
2947
2948 Status = ZwOpenFile(
2949 &hFile,
2950 0, // FILE_READ_ATTRIBUTES,
2951 &ObjectAttributes,
2952 &IoStatusBlock,
2953 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2954 0);
2955
2956 if (!NT_SUCCESS(Status))
2957 {
2958 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
2959 return FALSE;
2960 }
2961
2962 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
2963 ZwClose(hFile);
2964 if (!NT_SUCCESS(Status))
2965 {
2966 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
2967 return FALSE;
2968 }
2969
2970 return TRUE;
2971 }
2972
2973 BOOL
2974 FASTCALL
2975 IntGdiGetFontResourceInfo(
2976 PUNICODE_STRING FileName,
2977 PVOID pBuffer,
2978 DWORD *pdwBytes,
2979 DWORD dwType)
2980 {
2981 UNICODE_STRING EntryFileName;
2982 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
2983 PLIST_ENTRY ListEntry;
2984 PFONT_ENTRY FontEntry;
2985 FONTFAMILYINFO Info;
2986 ULONG Size;
2987 BOOL bFound = FALSE;
2988
2989 /* Create buffer for full path name */
2990 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
2991 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
2992 if (!NameInfo1)
2993 {
2994 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2995 return FALSE;
2996 }
2997
2998 /* Get the full path name */
2999 if (!IntGetFullFileName(NameInfo1, Size, FileName))
3000 {
3001 ExFreePoolWithTag(NameInfo1, TAG_FINF);
3002 return FALSE;
3003 }
3004
3005 /* Create a buffer for the entries' names */
3006 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
3007 if (!NameInfo2)
3008 {
3009 ExFreePoolWithTag(NameInfo1, TAG_FINF);
3010 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3011 return FALSE;
3012 }
3013
3014 /* Try to find the pathname in the global font list */
3015 IntLockGlobalFonts;
3016 for (ListEntry = FontListHead.Flink;
3017 ListEntry != &FontListHead;
3018 ListEntry = ListEntry->Flink)
3019 {
3020 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
3021 if (FontEntry->Font->Filename != NULL)
3022 {
3023 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
3024 if (IntGetFullFileName(NameInfo2, Size, &EntryFileName))
3025 {
3026 if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
3027 {
3028 /* Found */
3029 FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font);
3030 bFound = TRUE;
3031 break;
3032 }
3033 }
3034 }
3035 }
3036 IntUnLockGlobalFonts;
3037
3038 /* Free the buffers */
3039 ExFreePoolWithTag(NameInfo1, TAG_FINF);
3040 ExFreePool(NameInfo2);
3041
3042 if (!bFound && dwType != 5)
3043 {
3044 /* Font could not be found in system table
3045 dwType == 5 will still handle this */
3046 return FALSE;
3047 }
3048
3049 switch (dwType)
3050 {
3051 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
3052 *(DWORD*)pBuffer = 1;
3053 *pdwBytes = sizeof(DWORD);
3054 break;
3055
3056 case 1: /* Copy the full font name */
3057 Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1;
3058 Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR);
3059 RtlCopyMemory(pBuffer, Info.EnumLogFontEx.elfFullName, Size);
3060 // FIXME: Do we have to zeroterminate?
3061 *pdwBytes = Size;
3062 break;
3063
3064 case 2: /* Copy a LOGFONTW structure */
3065 Info.EnumLogFontEx.elfLogFont.lfWidth = 0;
3066 RtlCopyMemory(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
3067 *pdwBytes = sizeof(LOGFONTW);
3068 break;
3069
3070 case 3: /* FIXME: What exactly is copied here? */
3071 *(DWORD*)pBuffer = 1;
3072 *pdwBytes = sizeof(DWORD*);
3073 break;
3074
3075 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
3076 *(BOOL*)pBuffer = !bFound;
3077 *pdwBytes = sizeof(BOOL);
3078 break;
3079
3080 default:
3081 return FALSE;
3082 }
3083
3084 return TRUE;
3085 }
3086
3087
3088 BOOL
3089 FASTCALL
3090 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
3091 {
3092 if (FT_HAS_FIXED_SIZES(Font->face))
3093 Info->iTechnology = RI_TECH_BITMAP;
3094 else
3095 {
3096 if (FT_IS_SCALABLE(Font->face))
3097 Info->iTechnology = RI_TECH_SCALABLE;
3098 else
3099 Info->iTechnology = RI_TECH_FIXED;
3100 }
3101 Info->iUniq = Font->FontObj.iUniq;
3102 Info->dwUnknown = -1;
3103 return TRUE;
3104 }
3105
3106
3107 DWORD
3108 FASTCALL
3109 ftGdiGetKerningPairs( PFONTGDI Font,
3110 DWORD cPairs,
3111 LPKERNINGPAIR pKerningPair)
3112 {
3113 DWORD Count = 0;
3114 INT i = 0;
3115 FT_Face face = Font->face;
3116
3117 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
3118 {
3119 FT_UInt previous_index = 0, glyph_index = 0;
3120 FT_ULong char_code, char_previous;
3121 FT_Vector delta;
3122
3123 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
3124
3125 IntLockFreeType;
3126
3127 while (glyph_index)
3128 {
3129 if (previous_index && glyph_index)
3130 {
3131 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
3132
3133 if (pKerningPair && cPairs)
3134 {
3135 pKerningPair[i].wFirst = char_previous;
3136 pKerningPair[i].wSecond = char_code;
3137 pKerningPair[i].iKernAmount = delta.x;
3138 i++;
3139 if (i == cPairs) break;
3140 }
3141 Count++;
3142 }
3143 previous_index = glyph_index;
3144 char_previous = char_code;
3145 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
3146 }
3147 IntUnLockFreeType;
3148 }
3149 return Count;
3150 }
3151
3152
3153 ///////////////////////////////////////////////////////////////////////////
3154 //
3155 // Functions needing sorting.
3156 //
3157 ///////////////////////////////////////////////////////////////////////////
3158 int APIENTRY
3159 NtGdiGetFontFamilyInfo(HDC Dc,
3160 LPLOGFONTW UnsafeLogFont,
3161 PFONTFAMILYINFO UnsafeInfo,
3162 DWORD Size)
3163 {
3164 NTSTATUS Status;
3165 LOGFONTW LogFont;
3166 PFONTFAMILYINFO Info;
3167 DWORD Count;
3168 PPROCESSINFO Win32Process;
3169
3170 /* Make a safe copy */
3171 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
3172 if (! NT_SUCCESS(Status))
3173 {
3174 EngSetLastError(ERROR_INVALID_PARAMETER);
3175 return -1;
3176 }
3177
3178 /* Allocate space for a safe copy */
3179 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT);
3180 if (NULL == Info)
3181 {
3182 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3183 return -1;
3184 }
3185
3186 /* Enumerate font families in the global list */
3187 IntLockGlobalFonts;
3188 Count = 0;
3189 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
3190 {
3191 IntUnLockGlobalFonts;
3192 ExFreePoolWithTag(Info, GDITAG_TEXT);
3193 return -1;
3194 }
3195 IntUnLockGlobalFonts;
3196
3197 /* Enumerate font families in the process local list */
3198 Win32Process = PsGetCurrentProcessWin32Process();
3199 IntLockProcessPrivateFonts(Win32Process);
3200 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
3201 &Win32Process->PrivateFontListHead))
3202 {
3203 IntUnLockProcessPrivateFonts(Win32Process);
3204 ExFreePoolWithTag(Info, GDITAG_TEXT);
3205 return -1;
3206 }
3207 IntUnLockProcessPrivateFonts(Win32Process);
3208
3209 /* Enumerate font families in the registry */
3210 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
3211 {
3212 ExFreePoolWithTag(Info, GDITAG_TEXT);
3213 return -1;
3214 }
3215
3216 /* Return data to caller */
3217 if (0 != Count)
3218 {
3219 Status = MmCopyToCaller(UnsafeInfo, Info,
3220 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
3221 if (! NT_SUCCESS(Status))
3222 {
3223 ExFreePoolWithTag(Info, GDITAG_TEXT);
3224 EngSetLastError(ERROR_INVALID_PARAMETER);
3225 return -1;
3226 }
3227 }
3228
3229 ExFreePoolWithTag(Info, GDITAG_TEXT);
3230
3231 return Count;
3232 }
3233
3234 FORCEINLINE
3235 LONG
3236 ScaleLong(LONG lValue, PFLOATOBJ pef)
3237 {
3238 FLOATOBJ efTemp;
3239
3240 /* Check if we have scaling different from 1 */
3241 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
3242 {
3243 /* Need to multiply */
3244 FLOATOBJ_SetLong(&efTemp, lValue);
3245 FLOATOBJ_Mul(&efTemp, pef);
3246 lValue = FLOATOBJ_GetLong(&efTemp);
3247 }
3248
3249 return lValue;
3250 }
3251
3252 BOOL
3253 APIENTRY
3254 GreExtTextOutW(
3255 IN HDC hDC,
3256 IN INT XStart,
3257 IN INT YStart,
3258 IN UINT fuOptions,
3259 IN OPTIONAL PRECTL lprc,
3260 IN LPWSTR String,
3261 IN INT Count,
3262 IN OPTIONAL LPINT Dx,
3263 IN DWORD dwCodePage)
3264 {
3265 /*
3266 * FIXME:
3267 * Call EngTextOut, which does the real work (calling DrvTextOut where
3268 * appropriate)
3269 */
3270
3271 DC *dc;
3272 PDC_ATTR pdcattr;
3273 SURFOBJ *SurfObj;
3274 SURFACE *psurf = NULL;
3275 int error, glyph_index, n, i;
3276 FT_Face face;
3277 FT_GlyphSlot glyph;
3278 FT_BitmapGlyph realglyph;
3279 LONGLONG TextLeft, RealXStart;
3280 ULONG TextTop, previous, BackgroundLeft;
3281 FT_Bool use_kerning;
3282 RECTL DestRect, MaskRect;
3283 POINTL SourcePoint, BrushOrigin;
3284 HBITMAP HSourceGlyph;
3285 SURFOBJ *SourceGlyphSurf;
3286 SIZEL bitSize;
3287 FT_CharMap found = 0, charmap;
3288 INT yoff;
3289 FONTOBJ *FontObj;
3290 PFONTGDI FontGDI;
3291 PTEXTOBJ TextObj = NULL;
3292 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
3293 FT_Render_Mode RenderMode;
3294 BOOLEAN Render;
3295 POINT Start;
3296 BOOL DoBreak = FALSE;
3297 USHORT DxShift;
3298 PMATRIX pmxWorldToDevice;
3299 LONG fixAscender, fixDescender;
3300 FLOATOBJ Scale;
3301
3302 // TODO: Write test-cases to exactly match real Windows in different
3303 // bad parameters (e.g. does Windows check the DC or the RECT first?).
3304 dc = DC_LockDc(hDC);
3305 if (!dc)
3306 {
3307 EngSetLastError(ERROR_INVALID_HANDLE);
3308 return FALSE;
3309 }
3310 if (dc->dctype == DC_TYPE_INFO)
3311 {
3312 DC_UnlockDc(dc);
3313 /* Yes, Windows really returns TRUE in this case */
3314 return TRUE;
3315 }
3316
3317 pdcattr = dc->pdcattr;
3318
3319 if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE)
3320 {
3321 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
3322 DC_vUpdateBackgroundBrush(dc);
3323 }
3324
3325 /* Check if String is valid */
3326 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
3327 {
3328 EngSetLastError(ERROR_INVALID_PARAMETER);
3329 goto fail;
3330 }
3331
3332 DxShift = fuOptions & ETO_PDY ? 1 : 0;
3333
3334 if (PATH_IsPathOpen(dc->dclevel))
3335 {
3336 if (!PATH_ExtTextOut( dc,
3337 XStart,
3338 YStart,
3339 fuOptions,
3340 (const RECTL *)lprc,
3341 String,
3342 Count,
3343 (const INT *)Dx)) goto fail;
3344 goto good;
3345 }
3346
3347 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
3348 {
3349 IntLPtoDP(dc, (POINT *)lprc, 2);
3350 }
3351
3352 Start.x = XStart;
3353 Start.y = YStart;
3354 IntLPtoDP(dc, &Start, 1);
3355
3356 RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;
3357 YStart = Start.y + dc->ptlDCOrig.y;
3358
3359 SourcePoint.x = 0;
3360 SourcePoint.y = 0;
3361 MaskRect.left = 0;
3362 MaskRect.top = 0;
3363 BrushOrigin.x = 0;
3364 BrushOrigin.y = 0;
3365
3366 if ((fuOptions & ETO_OPAQUE) && lprc)
3367 {
3368 DestRect.left = lprc->left;
3369 DestRect.top = lprc->top;
3370 DestRect.right = lprc->right;
3371 DestRect.bottom = lprc->bottom;
3372
3373 DestRect.left += dc->ptlDCOrig.x;
3374 DestRect.top += dc->ptlDCOrig.y;
3375 DestRect.right += dc->ptlDCOrig.x;
3376 DestRect.bottom += dc->ptlDCOrig.y;
3377
3378 DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL);
3379
3380 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
3381 DC_vUpdateBackgroundBrush(dc);
3382
3383 IntEngBitBlt(
3384 &dc->dclevel.pSurface->SurfObj,
3385 NULL,
3386 NULL,
3387 &dc->co.ClipObj,
3388 NULL,
3389 &DestRect,
3390 &SourcePoint,
3391 &SourcePoint,
3392 &dc->eboBackground.BrushObject,
3393 &BrushOrigin,
3394 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
3395 fuOptions &= ~ETO_OPAQUE;
3396 DC_vFinishBlit(dc, NULL);
3397 }
3398 else
3399 {
3400 if (pdcattr->jBkMode == OPAQUE)
3401 {
3402 fuOptions |= ETO_OPAQUE;
3403 }
3404 }
3405
3406 TextObj = RealizeFontInit(pdcattr->hlfntNew);
3407 if (TextObj == NULL)
3408 {
3409 goto fail;
3410 }
3411
3412 FontObj = TextObj->Font;
3413 ASSERT(FontObj);
3414 FontGDI = ObjToGDI(FontObj, FONT);
3415 ASSERT(FontGDI);
3416
3417 IntLockFreeType;
3418 face = FontGDI->face;
3419 if (face->charmap == NULL)
3420 {
3421 DPRINT("WARNING: No charmap selected!\n");
3422 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3423
3424 for (n = 0; n < face->num_charmaps; n++)
3425 {
3426 charmap = face->charmaps[n];
3427 DPRINT("Found charmap encoding: %u\n", charmap->encoding);
3428 if (charmap->encoding != 0)
3429 {
3430 found = charmap;
3431 break;
3432 }
3433 }
3434 if (!found)
3435 {
3436 DPRINT1("WARNING: Could not find desired charmap!\n");
3437 }
3438 error = FT_Set_Charmap(face, found);
3439 if (error)
3440 {
3441 DPRINT1("WARNING: Could not set the charmap!\n");
3442 }
3443 }
3444
3445 Render = IntIsFontRenderingEnabled();
3446 if (Render)
3447 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
3448 else
3449 RenderMode = FT_RENDER_MODE_MONO;
3450
3451 error = FT_Set_Pixel_Sizes(
3452 face,
3453 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
3454 /* FIXME: Should set character height if neg */
3455 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
3456 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
3457 if (error)
3458 {
3459 DPRINT1("Error in setting pixel sizes: %d\n", error);
3460 IntUnLockFreeType;
3461 goto fail;
3462 }
3463
3464 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3465 FtSetCoordinateTransform(face, pmxWorldToDevice);
3466
3467 /*
3468 * Process the vertical alignment and determine the yoff.
3469 */
3470
3471 fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
3472 fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
3473
3474 if (pdcattr->lTextAlign & TA_BASELINE)
3475 yoff = 0;
3476 else if (pdcattr->lTextAlign & TA_BOTTOM)
3477 yoff = -fixDescender >> 6;
3478 else /* TA_TOP */
3479 yoff = fixAscender >> 6;
3480
3481 use_kerning = FT_HAS_KERNING(face);
3482 previous = 0;
3483
3484 /*
3485 * Process the horizontal alignment and modify XStart accordingly.
3486 */
3487
3488 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
3489 {
3490 ULONGLONG TextWidth = 0;
3491 LPCWSTR TempText = String;
3492 int Start;
3493
3494 /*
3495 * Calculate width of the text.
3496 */
3497
3498 if (NULL != Dx)
3499 {
3500 Start = Count < 2 ? 0 : Count - 2;
3501 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
3502 }
3503 else
3504 {
3505 Start = 0;
3506 }
3507 TempText = String + Start;
3508
3509 for (i = Start; i < Count; i++)
3510 {
3511 if (fuOptions & ETO_GLYPH_INDEX)
3512 glyph_index = *TempText;
3513 else
3514 glyph_index = FT_Get_Char_Index(face, *TempText);
3515
3516 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3517 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3518 pmxWorldToDevice)))
3519 {
3520 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3521 if (error)
3522 {
3523 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
3524 }
3525
3526 glyph = face->glyph;
3527 realglyph = ftGdiGlyphCacheSet(face,
3528 glyph_index,
3529 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3530 pmxWorldToDevice,
3531 glyph,
3532 RenderMode);
3533 if (!realglyph)
3534 {
3535 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3536 IntUnLockFreeType;
3537 goto fail;
3538 }
3539
3540 }
3541 /* Retrieve kerning distance */
3542 if (use_kerning && previous && glyph_index)
3543 {
3544 FT_Vector delta;
3545 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3546 TextWidth += delta.x;
3547 }
3548
3549 TextWidth += realglyph->root.advance.x >> 10;
3550
3551 previous = glyph_index;
3552 TempText++;
3553 }
3554
3555 previous = 0;
3556
3557 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
3558 {
3559 RealXStart -= TextWidth / 2;
3560 }
3561 else
3562 {
3563 RealXStart -= TextWidth;
3564 }
3565 }
3566
3567 TextLeft = RealXStart;
3568 TextTop = YStart;
3569 BackgroundLeft = (RealXStart + 32) >> 6;
3570
3571 /* Lock blit with a dummy rect */
3572 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
3573
3574 psurf = dc->dclevel.pSurface ;
3575 if(!psurf) psurf = psurfDefaultBitmap;
3576 SurfObj = &psurf->SurfObj ;
3577
3578 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
3579 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
3580
3581 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
3582 DC_vUpdateBackgroundBrush(dc) ;
3583
3584 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
3585 DC_vUpdateTextBrush(dc) ;
3586
3587 /*
3588 * The main rendering loop.
3589 */
3590 for (i = 0; i < Count; i++)
3591 {
3592 if (fuOptions & ETO_GLYPH_INDEX)
3593 glyph_index = *String;
3594 else
3595 glyph_index = FT_Get_Char_Index(face, *String);
3596
3597 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3598 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3599 pmxWorldToDevice)))
3600 {
3601 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3602 if (error)
3603 {
3604 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
3605 IntUnLockFreeType;
3606 DC_vFinishBlit(dc, NULL);
3607 goto fail2;
3608 }
3609 glyph = face->glyph;
3610 realglyph = ftGdiGlyphCacheSet(face,
3611 glyph_index,
3612 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3613 pmxWorldToDevice,
3614 glyph,
3615 RenderMode);
3616 if (!realglyph)
3617 {
3618 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3619 IntUnLockFreeType;
3620 DC_vFinishBlit(dc, NULL);
3621 goto fail2;
3622 }
3623 }
3624
3625 /* retrieve kerning distance and move pen position */
3626 if (use_kerning && previous && glyph_index && NULL == Dx)
3627 {
3628 FT_Vector delta;
3629 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3630 TextLeft += delta.x;
3631 }
3632 DPRINT("TextLeft: %I64d\n", TextLeft);
3633 DPRINT("TextTop: %lu\n", TextTop);
3634 DPRINT("Advance: %d\n", realglyph->root.advance.x);
3635
3636 if (fuOptions & ETO_OPAQUE)
3637 {
3638 DestRect.left = BackgroundLeft;
3639 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
3640 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
3641 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
3642 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
3643 IntEngBitBlt(
3644 &psurf->SurfObj,
3645 NULL,
3646 NULL,
3647 &dc->co.ClipObj,
3648 NULL,
3649 &DestRect,
3650 &SourcePoint,
3651 &SourcePoint,
3652 &dc->eboBackground.BrushObject,
3653 &BrushOrigin,
3654 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
3655 MouseSafetyOnDrawEnd(dc->ppdev);
3656 BackgroundLeft = DestRect.right;
3657
3658 }
3659
3660 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
3661 DestRect.right = DestRect.left + realglyph->bitmap.width;
3662 DestRect.top = TextTop + yoff - realglyph->top;
3663 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
3664
3665 bitSize.cx = realglyph->bitmap.width;
3666 bitSize.cy = realglyph->bitmap.rows;
3667 MaskRect.right = realglyph->bitmap.width;
3668 MaskRect.bottom = realglyph->bitmap.rows;
3669
3670 /*
3671 * We should create the bitmap out of the loop at the biggest possible
3672 * glyph size. Then use memset with 0 to clear it and sourcerect to
3673 * limit the work of the transbitblt.
3674 */
3675
3676 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
3677 BMF_8BPP, BMF_TOPDOWN,
3678 realglyph->bitmap.buffer);
3679 if ( !HSourceGlyph )
3680 {
3681 DPRINT1("WARNING: EngLockSurface() failed!\n");
3682 // FT_Done_Glyph(realglyph);
3683 IntUnLockFreeType;
3684 DC_vFinishBlit(dc, NULL);
3685 goto fail2;
3686 }
3687 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph<