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