2fe405f489ef3f6a4ab4caa15d6d04d6f7185f6b
[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 if ((fuOptions & ETO_OPAQUE) && lprc)
3369 {
3370 DestRect.left = lprc->left;
3371 DestRect.top = lprc->top;
3372 DestRect.right = lprc->right;
3373 DestRect.bottom = lprc->bottom;
3374
3375 DestRect.left += dc->ptlDCOrig.x;
3376 DestRect.top += dc->ptlDCOrig.y;
3377 DestRect.right += dc->ptlDCOrig.x;
3378 DestRect.bottom += dc->ptlDCOrig.y;
3379
3380 DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL);
3381
3382 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
3383 DC_vUpdateBackgroundBrush(dc);
3384
3385 IntEngBitBlt(
3386 &dc->dclevel.pSurface->SurfObj,
3387 NULL,
3388 NULL,
3389 &dc->co.ClipObj,
3390 NULL,
3391 &DestRect,
3392 &SourcePoint,
3393 &SourcePoint,
3394 &dc->eboBackground.BrushObject,
3395 &BrushOrigin,
3396 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
3397 fuOptions &= ~ETO_OPAQUE;
3398 DC_vFinishBlit(dc, NULL);
3399 }
3400 else
3401 {
3402 if (pdcattr->jBkMode == OPAQUE)
3403 {
3404 fuOptions |= ETO_OPAQUE;
3405 }
3406 }
3407
3408 TextObj = RealizeFontInit(pdcattr->hlfntNew);
3409 if (TextObj == NULL)
3410 {
3411 goto fail;
3412 }
3413
3414 FontObj = TextObj->Font;
3415 ASSERT(FontObj);
3416 FontGDI = ObjToGDI(FontObj, FONT);
3417 ASSERT(FontGDI);
3418
3419 IntLockFreeType;
3420 face = FontGDI->face;
3421 if (face->charmap == NULL)
3422 {
3423 DPRINT("WARNING: No charmap selected!\n");
3424 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3425
3426 for (n = 0; n < face->num_charmaps; n++)
3427 {
3428 charmap = face->charmaps[n];
3429 DPRINT("Found charmap encoding: %u\n", charmap->encoding);
3430 if (charmap->encoding != 0)
3431 {
3432 found = charmap;
3433 break;
3434 }
3435 }
3436 if (!found)
3437 {
3438 DPRINT1("WARNING: Could not find desired charmap!\n");
3439 }
3440 error = FT_Set_Charmap(face, found);
3441 if (error)
3442 {
3443 DPRINT1("WARNING: Could not set the charmap!\n");
3444 }
3445 }
3446
3447 Render = IntIsFontRenderingEnabled();
3448 if (Render)
3449 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
3450 else
3451 RenderMode = FT_RENDER_MODE_MONO;
3452
3453 error = FT_Set_Pixel_Sizes(
3454 face,
3455 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
3456 /* FIXME: Should set character height if neg */
3457 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
3458 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
3459 if (error)
3460 {
3461 DPRINT1("Error in setting pixel sizes: %d\n", error);
3462 IntUnLockFreeType;
3463 goto fail;
3464 }
3465
3466 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3467 FtSetCoordinateTransform(face, pmxWorldToDevice);
3468
3469 /*
3470 * Process the vertical alignment and determine the yoff.
3471 */
3472
3473 fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
3474 fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
3475
3476 if (pdcattr->lTextAlign & TA_BASELINE)
3477 yoff = 0;
3478 else if (pdcattr->lTextAlign & TA_BOTTOM)
3479 yoff = -fixDescender >> 6;
3480 else /* TA_TOP */
3481 yoff = fixAscender >> 6;
3482
3483 use_kerning = FT_HAS_KERNING(face);
3484 previous = 0;
3485
3486 /*
3487 * Process the horizontal alignment and modify XStart accordingly.
3488 */
3489
3490 if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
3491 {
3492 ULONGLONG TextWidth = 0;
3493 LPCWSTR TempText = String;
3494 int Start;
3495
3496 /*
3497 * Calculate width of the text.
3498 */
3499
3500 if (NULL != Dx)
3501 {
3502 Start = Count < 2 ? 0 : Count - 2;
3503 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
3504 }
3505 else
3506 {
3507 Start = 0;
3508 }
3509 TempText = String + Start;
3510
3511 for (i = Start; i < Count; i++)
3512 {
3513 if (fuOptions & ETO_GLYPH_INDEX)
3514 glyph_index = *TempText;
3515 else
3516 glyph_index = FT_Get_Char_Index(face, *TempText);
3517
3518 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3519 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3520 pmxWorldToDevice)))
3521 {
3522 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3523 if (error)
3524 {
3525 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index);
3526 }
3527
3528 glyph = face->glyph;
3529 realglyph = ftGdiGlyphCacheSet(face,
3530 glyph_index,
3531 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3532 pmxWorldToDevice,
3533 glyph,
3534 RenderMode);
3535 if (!realglyph)
3536 {
3537 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3538 IntUnLockFreeType;
3539 goto fail;
3540 }
3541
3542 }
3543 /* Retrieve kerning distance */
3544 if (use_kerning && previous && glyph_index)
3545 {
3546 FT_Vector delta;
3547 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3548 TextWidth += delta.x;
3549 }
3550
3551 TextWidth += realglyph->root.advance.x >> 10;
3552
3553 previous = glyph_index;
3554 TempText++;
3555 }
3556
3557 previous = 0;
3558
3559 if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
3560 {
3561 RealXStart -= TextWidth / 2;
3562 }
3563 else
3564 {
3565 RealXStart -= TextWidth;
3566 }
3567 }
3568
3569 TextLeft = RealXStart;
3570 TextTop = YStart;
3571 BackgroundLeft = (RealXStart + 32) >> 6;
3572
3573 /* Lock blit with a dummy rect */
3574 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
3575
3576 psurf = dc->dclevel.pSurface ;
3577 if(!psurf) psurf = psurfDefaultBitmap;
3578 SurfObj = &psurf->SurfObj ;
3579
3580 EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
3581 EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
3582
3583 if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
3584 DC_vUpdateBackgroundBrush(dc) ;
3585
3586 if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
3587 DC_vUpdateTextBrush(dc) ;
3588
3589 /*
3590 * The main rendering loop.
3591 */
3592 for (i = 0; i < Count; i++)
3593 {
3594 if (fuOptions & ETO_GLYPH_INDEX)
3595 glyph_index = *String;
3596 else
3597 glyph_index = FT_Get_Char_Index(face, *String);
3598
3599 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3600 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3601 pmxWorldToDevice)))
3602 {
3603 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3604 if (error)
3605 {
3606 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
3607 IntUnLockFreeType;
3608 DC_vFinishBlit(dc, NULL);
3609 goto fail2;
3610 }
3611 glyph = face->glyph;
3612 realglyph = ftGdiGlyphCacheSet(face,
3613 glyph_index,
3614 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3615 pmxWorldToDevice,
3616 glyph,
3617 RenderMode);
3618 if (!realglyph)
3619 {
3620 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
3621 IntUnLockFreeType;
3622 DC_vFinishBlit(dc, NULL);
3623 goto fail2;
3624 }
3625 }
3626
3627 /* retrieve kerning distance and move pen position */
3628 if (use_kerning && previous && glyph_index && NULL == Dx)
3629 {
3630 FT_Vector delta;
3631 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3632 TextLeft += delta.x;
3633 }
3634 DPRINT("TextLeft: %I64d\n", TextLeft);
3635 DPRINT("TextTop: %lu\n", TextTop);
3636 DPRINT("Advance: %d\n", realglyph->root.advance.x);
3637
3638 if (fuOptions & ETO_OPAQUE)
3639 {
3640 DestRect.left = BackgroundLeft;
3641 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
3642 DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
3643 DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
3644 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
3645 IntEngBitBlt(
3646 &psurf->SurfObj,
3647 NULL,
3648 NULL,
3649 &dc->co.ClipObj,
3650 NULL,
3651 &DestRect,
3652 &SourcePoint,
3653 &SourcePoint,
3654 &dc->eboBackground.BrushObject,
3655 &BrushOrigin,
3656 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
3657 MouseSafetyOnDrawEnd(dc->ppdev);
3658 BackgroundLeft = DestRect.right;
3659
3660 }
3661
3662 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
3663 DestRect.right = DestRect.left + realglyph->bitmap.width;
3664 DestRect.top = TextTop + yoff - realglyph->top;
3665 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
3666
3667 bitSize.cx = realglyph->bitmap.width;
3668 bitSize.cy = realglyph->bitmap.rows;
3669 MaskRect.right = realglyph->bitmap.width;
3670 MaskRect.bottom = realglyph->bitmap.rows;
3671
3672 /*
3673 * We should create the bitmap out of the loop at the biggest possible
3674 * glyph size. Then use memset with 0 to clear it and sourcerect to
3675 * limit the work of the transbitblt.
3676 */
3677
3678 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
3679 BMF_8BPP, BMF_TOPDOWN,
3680 realglyph->bitmap.buffer);
3681 if ( !HSourceGlyph )
3682 {
3683 DPRINT1("WARNING: EngLockSurface() failed!\n");
3684 // FT_Done_Glyph(realglyph);
3685 IntUnLockFreeType;
3686 DC_vFinishBlit(dc, NULL);
3687 goto fail2;
3688 }
3689 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
3690 if ( !SourceGlyphSurf )
3691 {
3692 EngDeleteSurface((HSURF)HSourceGlyph);
3693 DPRINT1("WARNING: EngLockSurface() failed!\n");
3694 IntUnLockFreeType;
3695 DC_vFinishBlit(dc, NULL);
3696 goto fail2;
3697 }
3698
3699 /*
3700 * Use the font data as a mask to paint onto the DCs surface using a
3701 * brush.
3702 */
3703
3704 if (lprc && (fuOptions & ETO_CLIPPED) &&
3705 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
3706 {
3707 // We do the check '>=' instead of '>' to possibly save an iteration
3708 // through this loop, since it's breaking after the drawing is done,
3709 // and x is always incremented.
3710 DestRect.right = lprc->right + dc->ptlDCOrig.x;
3711 DoBreak = TRUE;
3712 }
3713 if (lprc && (fuOptions & ETO_CLIPPED) &&
3714 DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
3715 {
3716 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
3717 }
3718 MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
3719 IntEngMaskBlt(
3720 SurfObj,
3721 SourceGlyphSurf,
3722 &dc->co.ClipObj,
3723 &exloRGB2Dst.xlo,
3724 &exloDst2RGB.xlo,
3725 &DestRect,
3726 (PPOINTL)&MaskRect,
3727 &dc->eboText.BrushObject,
3728 &BrushOrigin);
3729 MouseSafetyOnDrawEnd(dc->ppdev) ;
3730
3731 EngUnlockSurface(SourceGlyphSurf);
3732 EngDeleteSurface((HSURF)HSourceGlyph);
3733
3734 if (DoBreak)
3735 {
3736 break;
3737 }
3738
3739 if (NULL == Dx)
3740 {
3741 TextLeft += realglyph->root.advance.x >> 10;
3742 DPRINT("New TextLeft: %I64d\n", TextLeft);
3743 }
3744 else
3745 {
3746 // FIXME this should probably be a matrix transform with TextTop as well.
3747 Scale = pdcattr->mxWorldToDevice.efM11;
3748 if (_FLOATOBJ_Equal0(&Scale))
3749 FLOATOBJ_Set1(&Scale);
3750
3751 FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6); // do the shift before multiplying to preserve precision
3752 TextLeft += FLOATOBJ_GetLong(&Scale);
3753 DPRINT("New TextLeft2: %I64d\n", TextLeft);
3754 }
3755
3756 if (DxShift)
3757 {
3758 TextTop -= Dx[2 * i + 1] << 6;
3759 }
3760
3761 previous = glyph_index;
3762
3763 String++;
3764 }
3765 IntUnLockFreeType;
3766
3767 DC_vFinishBlit(dc, NULL) ;
3768 EXLATEOBJ_vCleanup(&exloRGB2Dst);
3769 EXLATEOBJ_vCleanup(&exloDst2RGB);
3770 if (TextObj != NULL)
3771 TEXTOBJ_UnlockText(TextObj);
3772 good:
3773 DC_UnlockDc( dc );
3774
3775 return TRUE;
3776
3777 fail2:
3778 EXLATEOBJ_vCleanup(&exloRGB2Dst);
3779 EXLATEOBJ_vCleanup(&exloDst2RGB);
3780 fail:
3781 if (TextObj != NULL)
3782 TEXTOBJ_UnlockText(TextObj);
3783
3784 DC_UnlockDc(dc);
3785
3786 return FALSE;
3787 }
3788
3789 #define STACK_TEXT_BUFFER_SIZE 100
3790 BOOL
3791 APIENTRY
3792 NtGdiExtTextOutW(
3793 IN HDC hDC,
3794 IN INT XStart,
3795 IN INT YStart,
3796 IN UINT fuOptions,
3797 IN OPTIONAL LPRECT UnsafeRect,
3798 IN LPWSTR UnsafeString,
3799 IN INT Count,
3800 IN OPTIONAL LPINT UnsafeDx,
3801 IN DWORD dwCodePage)
3802 {
3803 BOOL Result = FALSE;
3804 NTSTATUS Status = STATUS_SUCCESS;
3805 RECTL SafeRect;
3806 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
3807 PVOID Buffer = LocalBuffer;
3808 LPWSTR SafeString = NULL;
3809 LPINT SafeDx = NULL;
3810 ULONG BufSize, StringSize, DxSize = 0;
3811
3812 /* Check if String is valid */
3813 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
3814 {
3815 EngSetLastError(ERROR_INVALID_PARAMETER);
3816 return FALSE;
3817 }
3818
3819 if (Count > 0)
3820 {
3821 /* Calculate buffer size for string and Dx values */
3822 BufSize = StringSize = Count * sizeof(WCHAR);
3823 if (UnsafeDx)
3824 {
3825 /* If ETO_PDY is specified, we have pairs of INTs */
3826 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
3827 BufSize += DxSize;
3828 }
3829
3830 /* Check if our local buffer is large enough */
3831 if (BufSize > STACK_TEXT_BUFFER_SIZE)
3832 {
3833 /* It's not, allocate a temp buffer */
3834 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
3835 if (!Buffer)
3836 {
3837 return FALSE;
3838 }
3839 }
3840
3841 /* Probe and copy user mode data to the buffer */
3842 _SEH2_TRY
3843 {
3844 /* Put the Dx before the String to assure alignment of 4 */
3845 SafeString = (LPWSTR)(((ULONG_PTR)Buffer) + DxSize);
3846
3847 /* Probe and copy the string */
3848 ProbeForRead(UnsafeString, StringSize, 1);
3849 memcpy((PVOID)SafeString, UnsafeString, StringSize);
3850
3851 /* If we have Dx values... */
3852 if (UnsafeDx)
3853 {
3854 /* ... probe and copy them */
3855 SafeDx = Buffer;
3856 ProbeForRead(UnsafeDx, DxSize, 1);
3857 memcpy(SafeDx, UnsafeDx, DxSize);
3858 }
3859 }
3860 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3861 {
3862 Status = _SEH2_GetExceptionCode();
3863 }
3864 _SEH2_END
3865 if (!NT_SUCCESS(Status))
3866 {
3867 goto cleanup;
3868 }
3869 }
3870
3871 /* If we have a rect, copy it */
3872 if (UnsafeRect)
3873 {
3874 _SEH2_TRY
3875 {
3876 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
3877 SafeRect = *UnsafeRect;
3878 }
3879 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3880 {
3881 Status = _SEH2_GetExceptionCode();
3882 }
3883 _SEH2_END
3884 if (!NT_SUCCESS(Status))
3885 {
3886 goto cleanup;
3887 }
3888 }
3889
3890 /* Finally call the internal routine */
3891 Result = GreExtTextOutW(hDC,
3892 XStart,
3893 YStart,
3894 fuOptions,
3895 &SafeRect,
3896 SafeString,
3897 Count,
3898 SafeDx,
3899 dwCodePage);
3900
3901 cleanup:
3902 /* If we allocated a buffer, free it */
3903 if (Buffer != LocalBuffer)
3904 {
3905 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
3906 }
3907
3908 return Result;
3909 }
3910
3911
3912 /*
3913 * @implemented
3914 */
3915 BOOL
3916 APIENTRY
3917 NtGdiGetCharABCWidthsW(
3918 IN HDC hDC,
3919 IN UINT FirstChar,
3920 IN ULONG Count,
3921 IN OPTIONAL PWCHAR pwch,
3922 IN FLONG fl,
3923 OUT PVOID Buffer)
3924 {
3925 LPABC SafeBuff;
3926 LPABCFLOAT SafeBuffF = NULL;
3927 PDC dc;
3928 PDC_ATTR pdcattr;
3929 PTEXTOBJ TextObj;
3930 PFONTGDI FontGDI;
3931 FT_Face face;
3932 FT_CharMap charmap, found = NULL;
3933 UINT i, glyph_index, BufferSize;
3934 HFONT hFont = 0;
3935 NTSTATUS Status = STATUS_SUCCESS;
3936 PMATRIX pmxWorldToDevice;
3937
3938 if (pwch)
3939 {
3940 _SEH2_TRY
3941 {
3942 ProbeForRead(pwch,
3943 sizeof(PWSTR),
3944 1);
3945 }
3946 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3947 {
3948 Status = _SEH2_GetExceptionCode();
3949 }
3950 _SEH2_END;
3951 }
3952 if (!NT_SUCCESS(Status))
3953 {
3954 EngSetLastError(Status);
3955 return FALSE;
3956 }
3957
3958 if (!Buffer)
3959 {
3960 EngSetLastError(ERROR_INVALID_PARAMETER);
3961 return FALSE;
3962 }
3963
3964 BufferSize = Count * sizeof(ABC); // Same size!
3965 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
3966 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
3967 if (SafeBuff == NULL)
3968 {
3969 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
3970 return FALSE;
3971 }
3972
3973 dc = DC_LockDc(hDC);
3974 if (dc == NULL)
3975 {
3976 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
3977 EngSetLastError(ERROR_INVALID_HANDLE);
3978 return FALSE;
3979 }
3980 pdcattr = dc->pdcattr;
3981 hFont = pdcattr->hlfntNew;
3982 TextObj = RealizeFontInit(hFont);
3983
3984 /* Get the DC's world-to-device transformation matrix */
3985 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
3986 DC_UnlockDc(dc);
3987
3988 if (TextObj == NULL)
3989 {
3990 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
3991 EngSetLastError(ERROR_INVALID_HANDLE);
3992 return FALSE;
3993 }
3994
3995 FontGDI = ObjToGDI(TextObj->Font, FONT);
3996
3997 face = FontGDI->face;
3998 if (face->charmap == NULL)
3999 {
4000 for (i = 0; i < face->num_charmaps; i++)
4001 {
4002 charmap = face->charmaps[i];
4003 if (charmap->encoding != 0)
4004 {
4005 found = charmap;
4006 break;
4007 }
4008 }
4009
4010 if (!found)
4011 {
4012 DPRINT1("WARNING: Could not find desired charmap!\n");
4013 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
4014 EngSetLastError(ERROR_INVALID_HANDLE);
4015 return FALSE;
4016 }
4017
4018 IntLockFreeType;
4019 FT_Set_Charmap(face, found);
4020 IntUnLockFreeType;
4021 }
4022
4023 IntLockFreeType;
4024 FT_Set_Pixel_Sizes(face,
4025 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
4026 /* FIXME: Should set character height if neg */
4027 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
4028 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
4029 FtSetCoordinateTransform(face, pmxWorldToDevice);
4030
4031 for (i = FirstChar; i < FirstChar+Count; i++)
4032 {
4033 int adv, lsb, bbx, left, right;
4034
4035 if (pwch)
4036 {
4037 if (fl & GCABCW_INDICES)
4038 glyph_index = pwch[i - FirstChar];
4039 else
4040 glyph_index = FT_Get_Char_Index(face, pwch[i - FirstChar]);
4041 }
4042 else
4043 {
4044 if (fl & GCABCW_INDICES)
4045 glyph_index = i;
4046 else
4047 glyph_index = FT_Get_Char_Index(face, i);
4048 }
4049 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
4050
4051 left = (INT)face->glyph->metrics.horiBearingX & -64;
4052 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
4053 adv = (face->glyph->advance.x + 32) >> 6;
4054
4055 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
4056 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
4057
4058 lsb = left >> 6;
4059 bbx = (right - left) >> 6;
4060 /*
4061 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
4062 */
4063 if (!fl)
4064 {
4065 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
4066 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
4067 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
4068 }
4069 else
4070 {
4071 SafeBuff[i - FirstChar].abcA = lsb;
4072 SafeBuff[i - FirstChar].abcB = bbx;
4073 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
4074 }
4075 }
4076 IntUnLockFreeType;
4077 TEXTOBJ_UnlockText(TextObj);
4078 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
4079 if (! NT_SUCCESS(Status))
4080 {
4081 SetLastNtError(Status);
4082 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
4083 return FALSE;
4084 }
4085 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
4086 DPRINT("NtGdiGetCharABCWidths Worked!\n");
4087 return TRUE;
4088 }
4089
4090 /*
4091 * @implemented
4092 */
4093 BOOL
4094 APIENTRY
4095 NtGdiGetCharWidthW(
4096 IN HDC hDC,
4097 IN UINT FirstChar,
4098 IN UINT Count,
4099 IN OPTIONAL PWCHAR pwc,
4100 IN FLONG fl,
4101 OUT PVOID Buffer)
4102 {
4103 NTSTATUS Status = STATUS_SUCCESS;
4104 LPINT SafeBuff;
4105 PFLOAT SafeBuffF = NULL;
4106 PDC dc;
4107 PDC_ATTR pdcattr;
4108 PTEXTOBJ TextObj;
4109 PFONTGDI FontGDI;
4110 FT_Face face;
4111 FT_CharMap charmap, found = NULL;
4112 UINT i, glyph_index, BufferSize;
4113 HFONT hFont = 0;
4114 PMATRIX pmxWorldToDevice;
4115
4116 if (pwc)
4117 {
4118 _SEH2_TRY
4119 {
4120 ProbeForRead(pwc,
4121 sizeof(PWSTR),
4122 1);
4123 }
4124 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4125 {
4126 Status = _SEH2_GetExceptionCode();
4127 }
4128 _SEH2_END;
4129 }
4130 if (!NT_SUCCESS(Status))
4131 {
4132 EngSetLastError(Status);
4133 return FALSE;
4134 }
4135
4136 BufferSize = Count * sizeof(INT); // Same size!
4137 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
4138 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
4139 if (SafeBuff == NULL)
4140 {
4141 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4142 return FALSE;
4143 }
4144
4145 dc = DC_LockDc(hDC);
4146 if (dc == NULL)
4147 {
4148 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
4149 EngSetLastError(ERROR_INVALID_HANDLE);
4150 return FALSE;
4151 }
4152 pdcattr = dc->pdcattr;
4153 hFont = pdcattr->hlfntNew;
4154 TextObj = RealizeFontInit(hFont);
4155 /* Get the DC's world-to-device transformation matrix */
4156 pmxWorldToDevice = DC_pmxWorldToDevice(dc);
4157 DC_UnlockDc(dc);
4158
4159 if (TextObj == NULL)
4160 {
4161 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
4162 EngSetLastError(ERROR_INVALID_HANDLE);
4163 return FALSE;
4164 }
4165
4166 FontGDI = ObjToGDI(TextObj->Font, FONT);
4167
4168 face = FontGDI->face;
4169 if (face->charmap == NULL)
4170 {
4171 for (i = 0; i < face->num_charmaps; i++)
4172 {
4173 charmap = face->charmaps[i];
4174 if (charmap->encoding != 0)
4175 {
4176 found = charmap;
4177 break;
4178 }
4179 }
4180
4181 if (!found)
4182 {
4183 DPRINT1("WARNING: Could not find desired charmap!\n");
4184 ExFreePool(SafeBuff);
4185 EngSetLastError(ERROR_INVALID_HANDLE);
4186 return FALSE;
4187 }
4188
4189 IntLockFreeType;
4190 FT_Set_Charmap(face, found);
4191 IntUnLockFreeType;
4192 }
4193
4194 IntLockFreeType;
4195 FT_Set_Pixel_Sizes(face,
4196 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
4197 /* FIXME: Should set character height if neg */
4198 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
4199 dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
4200 FtSetCoordinateTransform(face, pmxWorldToDevice);
4201
4202 for (i = FirstChar; i < FirstChar+Count; i++)
4203 {
4204 if (pwc)
4205 {
4206 if (fl & GCW_INDICES)
4207 glyph_index = pwc[i - FirstChar];
4208 else
4209 glyph_index = FT_Get_Char_Index(face, pwc[i - FirstChar]);
4210 }
4211 else
4212 {
4213 if (fl & GCW_INDICES)
4214 glyph_index = i;
4215 else
4216 glyph_index = FT_Get_Char_Index(face, i);
4217 }
4218 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
4219 if (!fl)
4220 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
4221 else
4222 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
4223 }
4224 IntUnLockFreeType;
4225 TEXTOBJ_UnlockText(TextObj);
4226 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
4227 ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
4228 return TRUE;
4229 }
4230
4231 DWORD
4232 FASTCALL
4233 GreGetGlyphIndicesW(
4234 HDC hdc,
4235 LPWSTR pwc,
4236 INT cwc,
4237 LPWORD pgi,
4238 DWORD iMode,
4239 DWORD Unknown)
4240 {
4241 PDC dc;
4242 PDC_ATTR pdcattr;
4243 PTEXTOBJ TextObj;
4244 PFONTGDI FontGDI;
4245 HFONT hFont = 0;
4246 OUTLINETEXTMETRICW *potm;
4247 INT i;
4248 FT_Face face;
4249 WCHAR DefChar = 0xffff;
4250 PWSTR Buffer = NULL;
4251 ULONG Size;
4252
4253 if ((!pwc) && (!pgi)) return cwc;
4254
4255 dc = DC_LockDc(hdc);
4256 if (!dc)
4257 {
4258 EngSetLastError(ERROR_INVALID_HANDLE);
4259 return GDI_ERROR;
4260 }
4261 pdcattr = dc->pdcattr;
4262 hFont = pdcattr->hlfntNew;
4263 TextObj = RealizeFontInit(hFont);
4264 DC_UnlockDc(dc);
4265 if (!TextObj)
4266 {
4267 EngSetLastError(ERROR_INVALID_HANDLE);
4268 return GDI_ERROR;
4269 }
4270
4271 FontGDI = ObjToGDI(TextObj->Font, FONT);
4272 TEXTOBJ_UnlockText(TextObj);
4273
4274 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
4275 if (!Buffer)
4276 {
4277 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4278 return GDI_ERROR;
4279 }
4280
4281 if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f; /* Indicate non existence */
4282 else
4283 {
4284 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4285 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
4286 if (!potm)
4287 {
4288 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4289 cwc = GDI_ERROR;
4290 goto ErrorRet;
4291 }
4292 IntGetOutlineTextMetrics(FontGDI, Size, potm);
4293 DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
4294 ExFreePoolWithTag(potm, GDITAG_TEXT);
4295 }
4296
4297 IntLockFreeType;
4298 face = FontGDI->face;
4299
4300 for (i = 0; i < cwc; i++)
4301 {
4302 Buffer[i] = FT_Get_Char_Index(face, pwc[i]);
4303 if (Buffer[i] == 0)
4304 {
4305 if (DefChar == 0xffff && FT_IS_SFNT(face))
4306 {
4307 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
4308 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0);
4309 }
4310 Buffer[i] = DefChar;
4311 }
4312 }
4313
4314 IntUnLockFreeType;
4315
4316 RtlCopyMemory( pgi, Buffer, cwc*sizeof(WORD));
4317
4318 ErrorRet:
4319 if (Buffer) ExFreePoolWithTag(Buffer, GDITAG_TEXT);
4320 return cwc;
4321 }
4322
4323
4324 /*
4325 * @implemented
4326 */
4327 DWORD
4328 APIENTRY
4329 NtGdiGetGlyphIndicesW(
4330 IN HDC hdc,
4331 IN OPTIONAL LPWSTR UnSafepwc,
4332 IN INT cwc,
4333 OUT OPTIONAL LPWORD UnSafepgi,
4334 IN DWORD iMode)
4335 {
4336 PDC dc;
4337 PDC_ATTR pdcattr;
4338 PTEXTOBJ TextObj;
4339 PFONTGDI FontGDI;
4340 HFONT hFont = 0;
4341 NTSTATUS Status = STATUS_SUCCESS;
4342 OUTLINETEXTMETRICW *potm;
4343 INT i;
4344 FT_Face face;
4345 WCHAR DefChar = 0xffff;
4346 PWSTR Buffer = NULL;
4347 ULONG Size;
4348
4349 if ((!UnSafepwc) && (!UnSafepgi)) return cwc;
4350
4351 dc = DC_LockDc(hdc);
4352 if (!dc)
4353 {
4354 EngSetLastError(ERROR_INVALID_HANDLE);
4355 return GDI_ERROR;
4356 }
4357 pdcattr = dc->pdcattr;
4358 hFont = pdcattr->hlfntNew;
4359 TextObj = RealizeFontInit(hFont);
4360 DC_UnlockDc(dc);
4361 if (!TextObj)
4362 {
4363 EngSetLastError(ERROR_INVALID_HANDLE);
4364 return GDI_ERROR;
4365 }
4366
4367 FontGDI = ObjToGDI(TextObj->Font, FONT);
4368 TEXTOBJ_UnlockText(TextObj);
4369
4370 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
4371 if (!Buffer)
4372 {
4373 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4374 return GDI_ERROR;
4375 }
4376
4377 if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f; /* Indicate non existence */
4378 else
4379 {
4380 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4381 potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
4382 if (!potm)
4383 {
4384 Status = ERROR_NOT_ENOUGH_MEMORY;
4385 goto ErrorRet;
4386 }
4387 IntGetOutlineTextMetrics(FontGDI, Size, potm);
4388 DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
4389 ExFreePoolWithTag(potm, GDITAG_TEXT);
4390 }
4391
4392 _SEH2_TRY
4393 {
4394 ProbeForRead(UnSafepwc,
4395 sizeof(PWSTR),
4396 1);
4397 }
4398 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4399 {
4400 Status = _SEH2_GetExceptionCode();
4401 }
4402 _SEH2_END;
4403
4404 if (!NT_SUCCESS(Status)) goto ErrorRet;
4405
4406 IntLockFreeType;
4407 face = FontGDI->face;
4408
4409 if (DefChar == 0xffff && FT_IS_SFNT(face))
4410 {
4411 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
4412 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0);
4413 }
4414
4415 for (i = 0; i < cwc; i++)
4416 {
4417 Buffer[i] = FT_Get_Char_Index(face, UnSafepwc[i]); // FIXME: Unsafe!
4418 if (Buffer[i] == 0)
4419 {
4420 Buffer[i] = DefChar;
4421 }
4422 }
4423
4424 IntUnLockFreeType;
4425
4426 _SEH2_TRY
4427 {
4428 ProbeForWrite(UnSafepgi,
4429 sizeof(WORD),
4430 1);
4431 RtlCopyMemory(UnSafepgi,
4432 Buffer,
4433 cwc*sizeof(WORD));
4434 }
4435 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4436 {
4437 Status = _SEH2_GetExceptionCode();
4438 }
4439 _SEH2_END;
4440
4441 ErrorRet:
4442 ExFreePoolWithTag(Buffer, GDITAG_TEXT);
4443 if (NT_SUCCESS(Status)) return cwc;
4444 EngSetLastError(Status);
4445 return GDI_ERROR;
4446 }
4447
4448 /* EOF */