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