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