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