* Sync up to trunk head (r64716).
[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 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2668 {
2669 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2670 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2671 }
2672 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
2673 {
2674 Score += 49;
2675 }
2676 RtlFreeUnicodeString(&EntryFaceNameW);
2677 }
2678
2679 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2680 Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
2681 if (NULL == Otm)
2682 {
2683 return Score;
2684 }
2685 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2686
2687 if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
2688 (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
2689 {
2690 Score += 25;
2691 }
2692 if (LogFont->lfWeight != FW_DONTCARE)
2693 {
2694 if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
2695 {
2696 WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
2697 }
2698 else
2699 {
2700 WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
2701 }
2702 Score += (1000 - WeightDiff) / (1000 / 25);
2703 }
2704 else
2705 {
2706 Score += 25;
2707 }
2708
2709 ExFreePoolWithTag(Otm, GDITAG_TEXT);
2710
2711 return Score;
2712 }
2713
2714 static __inline VOID
2715 FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
2716 PUNICODE_STRING FaceName, PLIST_ENTRY Head)
2717 {
2718 PLIST_ENTRY Entry;
2719 PFONT_ENTRY CurrentEntry;
2720 FONTGDI *FontGDI;
2721 UINT Score;
2722 ASSERT(FontObj && MatchScore && LogFont && FaceName && Head);
2723 Entry = Head->Flink;
2724 while (Entry != Head)
2725 {
2726 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2727
2728 FontGDI = CurrentEntry->Font;
2729 ASSERT(FontGDI);
2730
2731 Score = GetFontScore(LogFont, FaceName, FontGDI);
2732 if (*MatchScore == 0 || *MatchScore < Score)
2733 {
2734 *FontObj = GDIToObj(FontGDI, FONT);
2735 *MatchScore = Score;
2736 }
2737 Entry = Entry->Flink;
2738 }
2739 }
2740
2741 static __inline BOOLEAN
2742 SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
2743 LPCWSTR Key)
2744 {
2745 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2746 NTSTATUS Status;
2747 UNICODE_STRING Value;
2748
2749 RtlInitUnicodeString(&Value, NULL);
2750
2751 QueryTable[0].QueryRoutine = NULL;
2752 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
2753 RTL_QUERY_REGISTRY_REQUIRED;
2754 QueryTable[0].Name = FaceName->Buffer;
2755 QueryTable[0].EntryContext = &Value;
2756 QueryTable[0].DefaultType = REG_NONE;
2757 QueryTable[0].DefaultData = NULL;
2758 QueryTable[0].DefaultLength = 0;
2759
2760 QueryTable[1].QueryRoutine = NULL;
2761 QueryTable[1].Name = NULL;
2762
2763 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2764 Key,
2765 QueryTable,
2766 NULL,
2767 NULL);
2768 if (NT_SUCCESS(Status))
2769 {
2770 RtlFreeUnicodeString(FaceName);
2771 *FaceName = Value;
2772 }
2773
2774 return NT_SUCCESS(Status);
2775 }
2776
2777 static __inline void
2778 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
2779 {
2780 if (10 < Level) /* Enough is enough */
2781 {
2782 return;
2783 }
2784
2785 if (SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
2786 {
2787 SubstituteFontFamily(FaceName, Level + 1);
2788 }
2789 }
2790
2791 static
2792 VOID
2793 FASTCALL
2794 IntFontType(PFONTGDI Font)
2795 {
2796 PS_FontInfoRec psfInfo;
2797 FT_ULong tmp_size = 0;
2798
2799 if (FT_HAS_MULTIPLE_MASTERS(Font->face))
2800 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
2801 if (FT_HAS_VERTICAL( Font->face ))
2802 Font->FontObj.flFontType |= FO_VERT_FACE;
2803 if (FT_IS_SCALABLE( Font->face ))
2804 Font->FontObj.flFontType |= FO_TYPE_RASTER;
2805 if (FT_IS_SFNT(Font->face))
2806 {
2807 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
2808 if (FT_Get_Sfnt_Table(Font->face, ft_sfnt_post))
2809 Font->FontObj.flFontType |= FO_POSTSCRIPT;
2810 }
2811 if (!FT_Get_PS_Font_Info(Font->face, &psfInfo ))
2812 {
2813 Font->FontObj.flFontType |= FO_POSTSCRIPT;
2814 }
2815 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
2816 if (!FT_Load_Sfnt_Table(Font->face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
2817 {
2818 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
2819 }
2820 }
2821
2822 NTSTATUS
2823 FASTCALL
2824 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
2825 {
2826 NTSTATUS Status = STATUS_SUCCESS;
2827 PTEXTOBJ TextObj;
2828 UNICODE_STRING FaceName;
2829 PPROCESSINFO Win32Process;
2830 UINT MatchScore;
2831
2832 if (!pTextObj)
2833 {
2834 TextObj = TEXTOBJ_LockText(FontHandle);
2835 if (NULL == TextObj)
2836 {
2837 return STATUS_INVALID_HANDLE;
2838 }
2839
2840 if (TextObj->fl & TEXTOBJECT_INIT)
2841 {
2842 TEXTOBJ_UnlockText(TextObj);
2843 return STATUS_SUCCESS;
2844 }
2845 }
2846 else
2847 TextObj = pTextObj;
2848
2849 if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName))
2850 {
2851 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
2852 return STATUS_NO_MEMORY;
2853 }
2854 SubstituteFontFamily(&FaceName, 0);
2855 MatchScore = 0;
2856 TextObj->Font = NULL;
2857
2858 /* First search private fonts */
2859 Win32Process = PsGetCurrentProcessWin32Process();
2860 IntLockProcessPrivateFonts(Win32Process);
2861 FindBestFontFromList(&TextObj->Font, &MatchScore,
2862 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
2863 &Win32Process->PrivateFontListHead);
2864 IntUnLockProcessPrivateFonts(Win32Process);
2865
2866 /* Search system fonts */
2867 IntLockGlobalFonts;
2868 FindBestFontFromList(&TextObj->Font, &MatchScore,
2869 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
2870 &FontListHead);
2871 IntUnLockGlobalFonts;
2872 if (NULL == TextObj->Font)
2873 {
2874 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
2875 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName);
2876 Status = STATUS_NOT_FOUND;
2877 }
2878 else
2879 {
2880 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
2881 // Need hdev, when freetype is loaded need to create DEVOBJ for
2882 // Consumer and Producer.
2883 TextObj->Font->iUniq = 1; // Now it can be cached.
2884 IntFontType(FontGdi);
2885 FontGdi->flType = TextObj->Font->flFontType;
2886 FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0;
2887 FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0;
2888 TextObj->fl |= TEXTOBJECT_INIT;
2889 Status = STATUS_SUCCESS;
2890 }
2891
2892 RtlFreeUnicodeString(&FaceName);
2893 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
2894
2895 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
2896
2897 return Status;
2898 }
2899
2900
2901 static
2902 BOOL
2903 FASTCALL
2904 IntGetFullFileName(
2905 POBJECT_NAME_INFORMATION NameInfo,
2906 ULONG Size,
2907 PUNICODE_STRING FileName)
2908 {
2909 NTSTATUS Status;
2910 OBJECT_ATTRIBUTES ObjectAttributes;
2911 HANDLE hFile;
2912 IO_STATUS_BLOCK IoStatusBlock;
2913 ULONG Desired;
2914
2915 InitializeObjectAttributes(&ObjectAttributes,
2916 FileName,
2917 OBJ_CASE_INSENSITIVE,
2918 NULL,
2919 NULL);
2920
2921 Status = ZwOpenFile(
2922 &hFile,
2923 0, // FILE_READ_ATTRIBUTES,
2924 &ObjectAttributes,
2925 &IoStatusBlock,
2926 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2927 0);
2928
2929 if (!NT_SUCCESS(Status))
2930 {
2931 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
2932 return FALSE;
2933 }
2934
2935 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
2936 ZwClose(hFile);
2937 if (!NT_SUCCESS(Status))
2938 {
2939 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
2940 return FALSE;
2941 }
2942
2943 return TRUE;
2944 }
2945
2946 BOOL
2947 FASTCALL
2948 IntGdiGetFontResourceInfo(
2949 PUNICODE_STRING FileName,
2950 PVOID pBuffer,
2951 DWORD *pdwBytes,
2952 DWORD dwType)
2953 {
2954 UNICODE_STRING EntryFileName;
2955 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
2956 PLIST_ENTRY ListEntry;
2957 PFONT_ENTRY FontEntry;
2958 FONTFAMILYINFO Info;
2959 ULONG Size;
2960 BOOL bFound = FALSE;
2961
2962 /* Create buffer for full path name */
2963 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
2964 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
2965 if (!NameInfo1)
2966 {
2967 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2968 return FALSE;
2969 }
2970
2971 /* Get the full path name */
2972 if (!IntGetFullFileName(NameInfo1, Size, FileName))
2973 {
2974 ExFreePoolWithTag(NameInfo1, TAG_FINF);
2975 return FALSE;
2976 }
2977
2978 /* Create a buffer for the entries' names */
2979 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
2980 if (!NameInfo2)
2981 {
2982 ExFreePoolWithTag(NameInfo1, TAG_FINF);
2983 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2984 return FALSE;
2985 }
2986
2987 /* Try to find the pathname in the global font list */
2988 IntLockGlobalFonts;
2989 for (ListEntry = FontListHead.Flink;
2990 ListEntry != &FontListHead;
2991 ListEntry = ListEntry->Flink)
2992 {
2993 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
2994 if (FontEntry->Font->Filename != NULL)
2995 {
2996 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
2997 if (IntGetFullFileName(NameInfo2, Size, &EntryFileName))
2998 {
2999 if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
3000 {
3001 /* Found */
3002 FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font);
3003 bFound = TRUE;
3004 break;
3005 }
3006 }
3007 }
3008 }
3009 IntUnLockGlobalFonts;
3010
3011 /* Free the buffers */
3012 ExFreePoolWithTag(NameInfo1, TAG_FINF);
3013 ExFreePool(NameInfo2);
3014
3015 if (!bFound && dwType != 5)
3016 {
3017 /* Font could not be found in system table
3018 dwType == 5 will still handle this */
3019 return FALSE;
3020 }
3021
3022 switch (dwType)
3023 {
3024 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
3025 *(DWORD*)pBuffer = 1;
3026 *pdwBytes = sizeof(DWORD);
3027 break;
3028
3029 case 1: /* Copy the full font name */
3030 Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1;
3031 Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR);
3032 RtlCopyMemory(pBuffer, Info.EnumLogFontEx.elfFullName, Size);
3033 // FIXME: Do we have to zeroterminate?
3034 *pdwBytes = Size;
3035 break;
3036
3037 case 2: /* Copy a LOGFONTW structure */
3038 Info.EnumLogFontEx.elfLogFont.lfWidth = 0;
3039 RtlCopyMemory(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
3040 *pdwBytes = sizeof(LOGFONTW);
3041 break;
3042
3043 case 3: /* FIXME: What exactly is copied here? */
3044 *(DWORD*)pBuffer = 1;
3045 *pdwBytes = sizeof(DWORD*);
3046 break;
3047
3048 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
3049 *(BOOL*)pBuffer = !bFound;
3050 *pdwBytes = sizeof(BOOL);
3051 break;
3052
3053 default:
3054 return FALSE;
3055 }
3056
3057 return TRUE;
3058 }
3059
3060
3061 BOOL
3062 FASTCALL
3063 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
3064 {
3065 if (FT_HAS_FIXED_SIZES(Font->face))
3066 Info->iTechnology = RI_TECH_BITMAP;
3067 else
3068 {
3069 if (FT_IS_SCALABLE(Font->face))
3070 Info->iTechnology = RI_TECH_SCALABLE;
3071 else
3072 Info->iTechnology = RI_TECH_FIXED;
3073 }
3074 Info->iUniq = Font->FontObj.iUniq;
3075 Info->dwUnknown = -1;
3076 return TRUE;
3077 }
3078
3079
3080 DWORD
3081 FASTCALL
3082 ftGdiGetKerningPairs( PFONTGDI Font,
3083 DWORD cPairs,
3084 LPKERNINGPAIR pKerningPair)
3085 {
3086 DWORD Count = 0;
3087 INT i = 0;
3088 FT_Face face = Font->face;
3089
3090 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
3091 {
3092 FT_UInt previous_index = 0, glyph_index = 0;
3093 FT_ULong char_code, char_previous;
3094 FT_Vector delta;
3095
3096 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
3097
3098 IntLockFreeType;
3099
3100 while (glyph_index)
3101 {
3102 if (previous_index && glyph_index)
3103 {
3104 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
3105
3106 if (pKerningPair && cPairs)
3107 {
3108 pKerningPair[i].wFirst = char_previous;
3109 pKerningPair[i].wSecond = char_code;
3110 pKerningPair[i].iKernAmount = delta.x;
3111 i++;
3112 if (i == cPairs) break;
3113 }
3114 Count++;
3115 }
3116 previous_index = glyph_index;
3117 char_previous = char_code;
3118 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
3119 }
3120 IntUnLockFreeType;
3121 }
3122 return Count;
3123 }
3124
3125
3126 ///////////////////////////////////////////////////////////////////////////
3127 //
3128 // Functions needing sorting.
3129 //
3130 ///////////////////////////////////////////////////////////////////////////
3131 int APIENTRY
3132 NtGdiGetFontFamilyInfo(HDC Dc,
3133 LPLOGFONTW UnsafeLogFont,
3134 PFONTFAMILYINFO UnsafeInfo,
3135 DWORD Size)
3136 {
3137 NTSTATUS Status;
3138 LOGFONTW LogFont;
3139 PFONTFAMILYINFO Info;
3140 DWORD Count;
3141 PPROCESSINFO Win32Process;
3142
3143 /* Make a safe copy */
3144 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
3145 if (! NT_SUCCESS(Status))
3146 {
3147 EngSetLastError(ERROR_INVALID_PARAMETER);
3148 return -1;
3149 }
3150
3151 /* Allocate space for a safe copy */
3152 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT);
3153 if (NULL == Info)
3154 {
3155 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3156 return -1;
3157 }
3158
3159 /* Enumerate font families in the global list */
3160 IntLockGlobalFonts;
3161 Count = 0;
3162 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
3163 {
3164 IntUnLockGlobalFonts;
3165 ExFreePoolWithTag(Info, GDITAG_TEXT);
3166 return -1;
3167 }
3168 IntUnLockGlobalFonts;
3169
3170 /* Enumerate font families in the process local list */
3171 Win32Process = PsGetCurrentProcessWin32Process();
3172 IntLockProcessPrivateFonts(Win32Process);
3173 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
3174 &Win32Process->PrivateFontListHead))
3175 {
3176 IntUnLockProcessPrivateFonts(Win32Process);
3177 ExFreePoolWithTag(Info, GDITAG_TEXT);
3178 return -1;
3179 }
3180 IntUnLockProcessPrivateFonts(Win32Process);
3181
3182 /* Enumerate font families in the registry */
3183 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
3184 {
3185 ExFreePoolWithTag(Info, GDITAG_TEXT);
3186 return -1;
3187 }
3188
3189 /* Return data to caller */
3190 if (0 != Count)
3191 {
3192 Status = MmCopyToCaller(UnsafeInfo, Info,
3193 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
3194 if (! NT_SUCCESS(Status))
3195 {
3196 ExFreePoolWithTag(Info, GDITAG_TEXT);
3197 EngSetLastError(ERROR_INVALID_PARAMETER);
3198 return -1;
3199 }
3200 }
3201
3202 ExFreePoolWithTag(Info, GDITAG_TEXT);
3203
3204 return Count;
3205 }
3206
3207 FORCEINLINE
3208 LONG
3209 ScaleLong(LONG lValue, PFLOATOBJ pef)
3210 {
3211 FLOATOBJ efTemp;
3212
3213 /* Check if we have scaling different from 1 */
3214 if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
3215 {
3216 /* Need to multiply */
3217 FLOATOBJ_SetLong(&efTemp, lValue);
3218 FLOATOBJ_Mul(&efTemp, pef);
3219 lValue = FLOATOBJ_GetLong(&efTemp);
3220 }
3221
3222 return lValue;
3223 }
3224
3225 BOOL
3226 APIENTRY
3227 GreExtTextOutW(
3228 IN HDC hDC,
3229 IN INT XStart,
3230 IN INT YStart,
3231 IN UINT fuOptions,
3232 IN OPTIONAL PRECTL lprc,
3233 IN LPWSTR String,
3234 IN INT Count,
3235 IN OPTIONAL LPINT Dx,
3236 IN DWORD dwCodePage)
3237 {
3238 /*
3239 * FIXME:
3240 * Call EngTextOut, which does the real work (calling DrvTextOut where
3241 * appropriate)
3242 */
3243
3244 DC *dc;
3245 PDC_ATTR pdcattr;
3246 SURFOBJ *SurfObj;
3247 SURFACE *psurf = NULL;
3248 int error, glyph_index, n, i;
3249 FT_Face face;
3250 FT_GlyphSlot glyph;
3251 FT_BitmapGlyph realglyph;
3252 LONGLONG TextLeft, RealXStart;
3253 ULONG TextTop, previous, BackgroundLeft;
3254 FT_Bool use_kerning;
3255 RECTL DestRect, MaskRect;
3256 POINTL SourcePoint, BrushOrigin;
3257 HBITMAP HSourceGlyph;
3258 SURFOBJ *SourceGlyphSurf;
3259 SIZEL bitSize;
3260 FT_CharMap found = 0, charmap;
3261 INT yoff;
3262 FONTOBJ *FontObj;
3263 PFONTGDI FontGDI;
3264 PTEXTOBJ TextObj = NULL;
3265 EXLATEOBJ exloRGB2Dst, exloDst2RGB;
3266 FT_Render_Mode RenderMode;
3267 BOOLEAN Render;
3268 POINT Start;
3269 BOOL DoBreak = FALSE;
3270 USHORT DxShift;
3271 PMATRIX pmxWorldToDevice;
3272 LONG fixAscender, fixDescender;
3273 FLOATOBJ Scale;
3274
3275 // TODO: Write test-cases to exactly match real Windows in different
3276 // bad parameters (e.g. does Windows check the DC or the RECT first?).
3277 dc = DC_LockDc(hDC);
3278 if (!dc)
3279 {
3280 EngSetLastError(ERROR_INVALID_HANDLE);
3281 return FALSE;
3282 }
3283 if (dc->dctype == DC_TYPE_INFO)
3284 {
3285 DC_UnlockDc(dc);
3286 /* Yes, Windows really returns TRUE in this case */
3287 return TRUE;
3288 }
3289
3290 pdcattr = dc->pdcattr;
3291
3292 if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE)
3293 {
3294 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
3295 DC_vUpdateBackgroundBrush(dc);
3296 }
3297
3298 /* Check if String is valid */
3299 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
3300 {
3301 EngSetLastError(ERROR_INVALID_PARAMETER);
3302 goto fail;
3303 }
3304
3305 DxShift = fuOptions & ETO_PDY ? 1 : 0;
3306
3307 if (PATH_IsPathOpen(dc->dclevel))
3308 {
3309 if (!PATH_ExtTextOut( dc,
3310 XStart,
3311 YStart,
3312 fuOptions,
3313 (const RECTL *)lprc,
3314 String,
3315 Count,
3316 (const INT *)Dx)) goto fail;
3317 goto good;
3318 }
3319
3320 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
3321 {
3322 IntLPtoDP(dc, (POINT *)lprc, 2);
3323 }
3324
3325 Start.x = XStart;
3326 Start.y = YStart;
3327 IntLPtoDP(dc, &Start, 1);
3328
3329 RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;
3330 YStart = Start.y + dc->ptlDCOrig.y;
3331
3332 SourcePoint.x = 0;
3333 SourcePoint.y = 0;
3334 MaskRect.left = 0;
3335 MaskRect.top = 0;
3336 BrushOrigin.x = 0;
3337 BrushOrigin.y = 0;
3338
3339 if ((fuOptions & ETO_OPAQUE) && lprc)
3340 {
3341 DestRect.left = lprc->left;
3342 DestRect.top = lprc->top;
3343 DestRect.right = lprc->right;
3344 DestRect.bottom = lprc->bottom;
3345
3346 DestRect.left += dc->ptlDCOrig.x;
3347 DestRect.top += dc->ptlDCOrig.y;
3348 DestRect.right += dc->ptlDCOrig.x;
3349 DestRect.bottom += dc->ptlDCOrig.y;
3350
3351 DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL);
3352
3353 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
3354 DC_vUpdateBackgroundBrush(dc);
3355
3356 IntEngBitBlt(
3357 &dc->dclevel.pSurface->SurfObj,
3358 NULL,
3359 NULL,
3360 &dc->co.ClipObj,
3361 NULL,
3362 &DestRect,
3363 &SourcePoint,
3364 &SourcePoint,
3365 &dc->eboBackground.BrushObject,
3366 &BrushOrigin,
3367 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
3368 fuOptions &= ~ETO_OPAQUE;
3369 DC_vFinishBlit(dc, NULL);
3370 }
3371 else
3372 {
3373 if (pdcattr->jBkMode == OPAQUE)
3374 {
3375 fuOptions |= ETO_OPAQUE;
3376 }
3377 }
3378
3379 TextObj = RealizeFontInit(pdcattr->hlfntNew);
3380 if (TextObj == NULL)
3381 {
3382 goto fail;
3383 }
3384
3385 FontObj = TextObj->Font;
3386 ASSERT(FontObj);
3387 FontGDI = ObjToGDI(FontObj, FONT);
3388 ASSERT(FontGDI);
3389
3390 IntLockFreeType;
3391 face = FontGDI->face;
3392 if (face->charmap == NULL)
3393 {
3394 DPRINT("WARNING: No charmap selected!\n");
3395 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3396
3397 for (n = 0; n < face->num_charmaps; n++)
3398 {
3399 charmap = face->charmaps[n];
3400 DPRINT("Found charmap encoding: %u\n", charmap->encoding);
3401 if (charmap->encoding != 0)
3402 {
3403 found = charmap;
3404 break;
3405 }
3406 }
3407 if (!found)
3408 {
3409 DPRINT1("WARNING: Could not find desired charmap!\n");
3410 }
3411 error = FT_Set_Charmap(face, found);
3412 if (error)
3413 {
3414 DPRINT1("WARNING: Could not set the charmap!\n");
3415 }
3416 }
3417
3418 Render = IntIsFontRenderingEnabled();
3419 if (Render)
3420 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
3421 else
3422 RenderMode = FT_RENDER_MODE_MONO;
3423
3424 error = FT_Set_Pixel_Sizes(
3425 face,
3426 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
3427 /* FIXME: Should set character height if neg */
3428 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
3429 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
3430 if (error)
3431 {
3432 DPRINT1("Error in setting pixel sizes: %d\n", error);
3433 IntUnLockFreeType;
3434 goto fail;
3435 }
3436
3437 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3438 FtSetCoordinateTransform(face, pmxWorldToDevice);
3439
3440 /*
3441 * Process the vertical alignment and determine the yoff.
3442 */
3443
3444 fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
3445 fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
3446
3447 if (pdcattr->lTextAlign & TA_BASELINE)
3448 yoff = 0;
3449 else if (pdcattr->lTextAlign & TA_BOTTOM)
3450 yoff = -fixDescender >> 6;
3451 else /* TA_TOP */
3452 yoff = fixAscender >> 6;
3453
3454 use_kerning = FT_HAS_KERNING(face);
3455 previous = 0;
3456
3457 /*
3458 * Process the horizontal alignment and modify XStart accordingly.
3459 */
3460
3461 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
3462 {
3463 ULONGLONG TextWidth = 0;
3464 LPCWSTR TempText = String;
3465 int Start;
3466
3467 /*
3468 * Calculate width of the text.
3469 */
3470
3471 if (NULL != Dx)
3472 {
3473 Start = Count < 2 ? 0 : Count - 2;
3474 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
3475 }
3476 else
3477 {
3478 Start = 0;
3479 }
3480 TempText = String + Start;
3481
3482 for (i = Start; i < Count; i++)
3483 {
3484 if (fuOptions & ETO_GLYPH_INDEX)
3485 glyph_index = *TempText;
3486 else
3487 glyph_index = FT_Get_Char_Index(face, *TempText);
3488
3489 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3490 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3491 pmxWorldToDevice)))
3492 {
3493 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3494 if (error)
3495 {
3496 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
3497 }
3498
3499 glyph = face->glyph;
3500 realglyph = ftGdiGlyphCacheSet(face,
3501 glyph_index,
3502 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3503 pmxWorldToDevice,
3504 glyph,
3505 RenderMode);
3506 if (!realglyph)
3507 {
3508 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3509 IntUnLockFreeType;
3510 goto fail;
3511 }
3512
3513 }
3514 /* Retrieve kerning distance */
3515 if (use_kerning && previous && glyph_index)
3516 {
3517 FT_Vector delta;
3518 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3519 TextWidth += delta.x;
3520 }
3521
3522 TextWidth += realglyph->root.advance.x >> 10;
3523
3524 previous = glyph_index;
3525 TempText++;
3526 }
3527
3528 previous = 0;
3529
3530 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
3531 {
3532 RealXStart -= TextWidth / 2;
3533 }
3534 else
3535 {
3536 RealXStart -= TextWidth;
3537 }
3538 }
3539
3540 TextLeft = RealXStart;
3541 TextTop = YStart;
3542 BackgroundLeft = (RealXStart + 32) >> 6;
3543
3544 /* Lock blit with a dummy rect */
3545 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
3546
3547 psurf = dc->dclevel.pSurface ;
3548 if(!psurf) psurf = psurfDefaultBitmap;
3549 SurfObj = &psurf->SurfObj ;
3550
3551 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
3552 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
3553
3554 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
3555 DC_vUpdateBackgroundBrush(dc) ;
3556
3557 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
3558 DC_vUpdateTextBrush(dc) ;
3559
3560 /*
3561 * The main rendering loop.
3562 */
3563 for (i = 0; i < Count; i++)
3564 {
3565 if (fuOptions & ETO_GLYPH_INDEX)
3566 glyph_index = *String;
3567 else
3568 glyph_index = FT_Get_Char_Index(face, *String);
3569
3570 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3571 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3572 pmxWorldToDevice)))
3573 {
3574 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3575 if (error)
3576 {
3577 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
3578 IntUnLockFreeType;
3579 DC_vFinishBlit(dc, NULL);
3580 goto fail2;
3581 }
3582 glyph = face->glyph;
3583 realglyph = ftGdiGlyphCacheSet(face,
3584 glyph_index,
3585 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3586 pmxWorldToDevice,
3587 glyph,
3588 RenderMode);
3589 if (!realglyph)
3590 {
3591 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3592 IntUnLockFreeType;
3593 DC_vFinishBlit(dc, NULL);
3594 goto fail2;
3595 }
3596 }
3597
3598 /* retrieve kerning distance and move pen position */
3599 if (use_kerning && previous && glyph_index && NULL == Dx)
3600 {
3601 FT_Vector delta;
3602 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3603 TextLeft += delta.x;
3604 }
3605 DPRINT("TextLeft: %I64d\n", TextLeft);
3606 DPRINT("TextTop: %lu\n", TextTop);
3607 DPRINT("Advance: %d\n", realglyph->root.advance.x);
3608
3609 if (fuOptions & ETO_OPAQUE)
3610 {
3611 DestRect.left = BackgroundLeft;
3612 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
3613 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
3614 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
3615 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
3616 IntEngBitBlt(
3617 &psurf->SurfObj,
3618 NULL,
3619 NULL,
3620 &dc->co.ClipObj,
3621 NULL,
3622 &DestRect,
3623 &SourcePoint,
3624 &SourcePoint,
3625 &dc->eboBackground.BrushObject,
3626 &BrushOrigin,
3627 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
3628 MouseSafetyOnDrawEnd(dc->ppdev);
3629 BackgroundLeft = DestRect.right;
3630
3631 }
3632
3633 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
3634 DestRect.right = DestRect.left + realglyph->bitmap.width;
3635 DestRect.top = TextTop + yoff - realglyph->top;
3636 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
3637
3638 bitSize.cx = realglyph->bitmap.width;
3639 bitSize.cy = realglyph->bitmap.rows;
3640 MaskRect.right = realglyph->bitmap.width;
3641 MaskRect.bottom = realglyph->bitmap.rows;
3642
3643 /*
3644 * We should create the bitmap out of the loop at the biggest possible
3645 * glyph size. Then use memset with 0 to clear it and sourcerect to
3646 * limit the work of the transbitblt.
3647 */
3648
3649 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
3650 BMF_8BPP, BMF_TOPDOWN,
3651 realglyph->bitmap.buffer);
3652 if ( !HSourceGlyph )
3653 {
3654 DPRINT1("WARNING: EngLockSurface() failed!\n");
3655 // FT_Done_Glyph(realglyph);
3656 IntUnLockFreeType;
3657 DC_vFinishBlit(dc, NULL);
3658 goto fail2;
3659 }
3660 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
3661 if ( !SourceGlyphSurf )
3662 {
3663 EngDeleteSurface((HSURF)HSourceGlyph);
3664 DPRINT1("WARNING: EngLockSurface() failed!\n");
3665 IntUnLockFreeType;
3666 DC_vFinishBlit(dc, NULL);
3667 goto fail2;
3668 }
3669
3670 /*
3671 * Use the font data as a mask to paint onto the DCs surface using a
3672 * brush.
3673 */
3674
3675 if (lprc && (fuOptions & ETO_CLIPPED) &&
3676 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
3677 {
3678 // We do the check '>=' instead of '>' to possibly save an iteration
3679 // through this loop, since it's breaking after the drawing is done,
3680 // and x is always incremented.
3681 DestRect.right = lprc->right + dc->ptlDCOrig.x;
3682 DoBreak = TRUE;
3683 }
3684 if (lprc && (fuOptions & ETO_CLIPPED) &&
3685 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
3686 {
3687 DestRect.bottom = lprc->bottom + dc->