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