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