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