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