Sync to trunk head (r40091)
[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/ftoutln.h>
48 #include <freetype/ftwinfnt.h>
49
50 #define NDEBUG
51 #include <debug.h>
52
53 #ifndef FT_MAKE_TAG
54 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
55 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
56 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
57 #endif
58
59 FT_Library library;
60
61 typedef struct _FONT_ENTRY
62 {
63 LIST_ENTRY ListEntry;
64 FONTGDI *Font;
65 UNICODE_STRING FaceName;
66 BYTE NotEnum;
67 } FONT_ENTRY, *PFONT_ENTRY;
68
69 /* The FreeType library is not thread safe, so we have
70 to serialize access to it */
71 static FAST_MUTEX FreeTypeLock;
72
73 static LIST_ENTRY FontListHead;
74 static FAST_MUTEX FontListLock;
75 static BOOL RenderingEnabled = TRUE;
76
77 #define MAX_FONT_CACHE 256
78 UINT Hits;
79 UINT Misses;
80
81 typedef struct _FONT_CACHE_ENTRY
82 {
83 LIST_ENTRY ListEntry;
84 int GlyphIndex;
85 FT_Face Face;
86 FT_Glyph Glyph;
87 int Height;
88 } FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY;
89 static LIST_ENTRY FontCacheListHead;
90 static UINT FontCacheNumEntries;
91
92 static PWCHAR ElfScripts[32] = /* these are in the order of the fsCsb[0] bits */
93 {
94 L"Western", /*00*/
95 L"Central_European",
96 L"Cyrillic",
97 L"Greek",
98 L"Turkish",
99 L"Hebrew",
100 L"Arabic",
101 L"Baltic",
102 L"Vietnamese", /*08*/
103 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
104 L"Thai",
105 L"Japanese",
106 L"CHINESE_GB2312",
107 L"Hangul",
108 L"CHINESE_BIG5",
109 L"Hangul(Johab)",
110 NULL, NULL, /*23*/
111 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
112 L"Symbol" /*31*/
113 };
114
115 /*
116 * For TranslateCharsetInfo
117 */
118 #define CP_SYMBOL 42
119 #define MAXTCIINDEX 32
120 static const CHARSETINFO FontTci[MAXTCIINDEX] =
121 {
122 /* ANSI */
123 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
124 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
125 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
126 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
127 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
128 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
129 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
130 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
131 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
132 /* reserved by ANSI */
133 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
134 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
135 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
136 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
137 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
138 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
139 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
140 /* ANSI and OEM */
141 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
142 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
143 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
144 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
145 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
146 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
147 /* reserved for alternate ANSI and OEM */
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 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
156 /* reserved for system */
157 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
158 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
159 };
160
161 BOOL FASTCALL
162 InitFontSupport(VOID)
163 {
164 ULONG ulError;
165
166 InitializeListHead(&FontListHead);
167 InitializeListHead(&FontCacheListHead);
168 FontCacheNumEntries = 0;
169 ExInitializeFastMutex(&FontListLock);
170 ExInitializeFastMutex(&FreeTypeLock);
171
172 ulError = FT_Init_FreeType(&library);
173 if (ulError)
174 {
175 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
176 return FALSE;
177 }
178
179 IntLoadSystemFonts();
180
181 return TRUE;
182 }
183
184 /*
185 * IntLoadSystemFonts
186 *
187 * Search the system font directory and adds each font found.
188 */
189
190 VOID FASTCALL
191 IntLoadSystemFonts(VOID)
192 {
193 OBJECT_ATTRIBUTES ObjectAttributes;
194 UNICODE_STRING Directory, SearchPattern, FileName, TempString;
195 IO_STATUS_BLOCK Iosb;
196 HANDLE hDirectory;
197 BYTE *DirInfoBuffer;
198 PFILE_DIRECTORY_INFORMATION DirInfo;
199 BOOLEAN bRestartScan = TRUE;
200 NTSTATUS Status;
201
202 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
203 /* FIXME: Add support for other font types */
204 RtlInitUnicodeString(&SearchPattern, L"*.ttf");
205
206 InitializeObjectAttributes(
207 &ObjectAttributes,
208 &Directory,
209 OBJ_CASE_INSENSITIVE,
210 NULL,
211 NULL);
212
213 Status = ZwOpenFile(
214 &hDirectory,
215 SYNCHRONIZE | FILE_LIST_DIRECTORY,
216 &ObjectAttributes,
217 &Iosb,
218 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
219 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
220
221 if (NT_SUCCESS(Status))
222 {
223 DirInfoBuffer = ExAllocatePool(PagedPool, 0x4000);
224 if (DirInfoBuffer == NULL)
225 {
226 ZwClose(hDirectory);
227 return;
228 }
229
230 FileName.Buffer = ExAllocatePool(PagedPool, MAX_PATH * sizeof(WCHAR));
231 if (FileName.Buffer == NULL)
232 {
233 ExFreePool(DirInfoBuffer);
234 ZwClose(hDirectory);
235 return;
236 }
237 FileName.Length = 0;
238 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
239
240 while (1)
241 {
242 Status = ZwQueryDirectoryFile(
243 hDirectory,
244 NULL,
245 NULL,
246 NULL,
247 &Iosb,
248 DirInfoBuffer,
249 0x4000,
250 FileDirectoryInformation,
251 FALSE,
252 &SearchPattern,
253 bRestartScan);
254
255 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
256 {
257 break;
258 }
259
260 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
261 while (1)
262 {
263 TempString.Buffer = DirInfo->FileName;
264 TempString.Length =
265 TempString.MaximumLength = DirInfo->FileNameLength;
266 RtlCopyUnicodeString(&FileName, &Directory);
267 RtlAppendUnicodeStringToString(&FileName, &TempString);
268 IntGdiAddFontResource(&FileName, 0);
269 if (DirInfo->NextEntryOffset == 0)
270 break;
271 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
272 }
273
274 bRestartScan = FALSE;
275 }
276
277 ExFreePool(FileName.Buffer);
278 ExFreePool(DirInfoBuffer);
279 ZwClose(hDirectory);
280 }
281 }
282
283
284 /*
285 * IntGdiAddFontResource
286 *
287 * Adds the font resource from the specified file to the system.
288 */
289
290 INT FASTCALL
291 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
292 {
293 FONTGDI *FontGDI;
294 NTSTATUS Status;
295 HANDLE FileHandle, KeyHandle;
296 OBJECT_ATTRIBUTES ObjectAttributes;
297 PVOID Buffer = NULL;
298 IO_STATUS_BLOCK Iosb;
299 INT Error;
300 FT_Face Face;
301 ANSI_STRING AnsiFaceName;
302 PFONT_ENTRY Entry;
303 PSECTION_OBJECT SectionObject;
304 ULONG ViewSize = 0;
305 LARGE_INTEGER SectionSize;
306 FT_Fixed XScale, YScale;
307 UNICODE_STRING FontRegPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
308
309 /* Open the font file */
310
311 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
312 Status = ZwOpenFile(
313 &FileHandle,
314 FILE_GENERIC_READ | SYNCHRONIZE,
315 &ObjectAttributes,
316 &Iosb,
317 FILE_SHARE_READ,
318 FILE_SYNCHRONOUS_IO_NONALERT);
319
320 if (!NT_SUCCESS(Status))
321 {
322 DPRINT("Could not load font file: %wZ\n", FileName);
323 return 0;
324 }
325
326 SectionSize.QuadPart = 0LL;
327 Status = MmCreateSection((PVOID)&SectionObject, SECTION_ALL_ACCESS,
328 NULL, &SectionSize, PAGE_READONLY,
329 SEC_COMMIT, FileHandle, NULL);
330 if (!NT_SUCCESS(Status))
331 {
332 DPRINT("Could not map file: %wZ\n", FileName);
333 ZwClose(FileHandle);
334 return 0;
335 }
336
337 ZwClose(FileHandle);
338
339 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
340 if (!NT_SUCCESS(Status))
341 {
342 DPRINT("Could not map file: %wZ\n", FileName);
343 return Status;
344 }
345
346 IntLockFreeType;
347 Error = FT_New_Memory_Face(
348 library,
349 Buffer,
350 ViewSize,
351 0,
352 &Face);
353 IntUnLockFreeType;
354
355 if (Error)
356 {
357 if (Error == FT_Err_Unknown_File_Format)
358 DPRINT("Unknown font file format\n");
359 else
360 DPRINT("Error reading font file (error code: %u)\n", Error);
361 ObDereferenceObject(SectionObject);
362 return 0;
363 }
364
365 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
366 if (!Entry)
367 {
368 FT_Done_Face(Face);
369 ObDereferenceObject(SectionObject);
370 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
371 return 0;
372 }
373
374 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), TAG_FONTOBJ);
375 if (FontGDI == NULL)
376 {
377 FT_Done_Face(Face);
378 ObDereferenceObject(SectionObject);
379 ExFreePoolWithTag(Entry, TAG_FONT);
380 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
381 return 0;
382 }
383
384 FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, FileName->Length + sizeof(WCHAR), TAG_PFF);
385 if (FontGDI->Filename == NULL)
386 {
387 EngFreeMem(FontGDI);
388 FT_Done_Face(Face);
389 ObDereferenceObject(SectionObject);
390 ExFreePoolWithTag(Entry, TAG_FONT);
391 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
392 return 0;
393 }
394 RtlCopyMemory(FontGDI->Filename, FileName->Buffer, FileName->Length);
395 FontGDI->Filename[FileName->Length / sizeof(WCHAR)] = L'\0';
396 FontGDI->face = Face;
397
398 /* FIXME: Complete text metrics */
399 XScale = Face->size->metrics.x_scale;
400 YScale = Face->size->metrics.y_scale;
401 #if 0 /* This (Wine) code doesn't seem to work correctly for us */
402 FontGDI->TextMetric.tmAscent = (FT_MulFix(Face->ascender, YScale) + 32) >> 6;
403 FontGDI->TextMetric.tmDescent = (FT_MulFix(Face->descender, YScale) + 32) >> 6;
404 FontGDI->TextMetric.tmHeight = (FT_MulFix(Face->ascender, YScale) -
405 FT_MulFix(Face->descender, YScale)) >> 6;
406 #else
407 FontGDI->TextMetric.tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
408 FontGDI->TextMetric.tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
409 FontGDI->TextMetric.tmHeight = (Face->size->metrics.ascender - Face->size->metrics.descender) >> 6;
410 #endif
411
412
413
414 DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
415 DPRINT("Num glyphs: %u\n", Face->num_glyphs);
416
417 /* Add this font resource to the font table */
418
419 Entry->Font = FontGDI;
420 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
421 RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name);
422 RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
423
424 if (Characteristics & FR_PRIVATE)
425 {
426 PW32PROCESS Win32Process = PsGetCurrentProcessWin32Process();
427 IntLockProcessPrivateFonts(Win32Process);
428 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
429 IntUnLockProcessPrivateFonts(Win32Process);
430 }
431 else
432 {
433 IntLockGlobalFonts;
434 InsertTailList(&FontListHead, &Entry->ListEntry);
435 InitializeObjectAttributes(&ObjectAttributes, &FontRegPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
436 Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
437 if (NT_SUCCESS(Status))
438 {
439 LPWSTR pName = wcsrchr(FileName->Buffer, L'\\');
440 if (pName)
441 {
442 pName++;
443 ZwSetValueKey(KeyHandle, &Entry->FaceName, 0, REG_SZ, pName, (wcslen(pName) + 1) * sizeof(WCHAR));
444 }
445 ZwClose(KeyHandle);
446 }
447 IntUnLockGlobalFonts;
448 }
449 return 1;
450 }
451
452 BOOL FASTCALL
453 IntIsFontRenderingEnabled(VOID)
454 {
455 BOOL Ret = RenderingEnabled;
456 HDC hDC;
457
458 hDC = IntGetScreenDC();
459 if (hDC)
460 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
461
462 return Ret;
463 }
464
465 VOID FASTCALL
466 IntEnableFontRendering(BOOL Enable)
467 {
468 RenderingEnabled = Enable;
469 }
470
471 FT_Render_Mode FASTCALL
472 IntGetFontRenderMode(LOGFONTW *logfont)
473 {
474 switch (logfont->lfQuality)
475 {
476 case NONANTIALIASED_QUALITY:
477 return FT_RENDER_MODE_MONO;
478 case DRAFT_QUALITY:
479 return FT_RENDER_MODE_LIGHT;
480 /* case CLEARTYPE_QUALITY:
481 return FT_RENDER_MODE_LCD; */
482 }
483 return FT_RENDER_MODE_NORMAL;
484 }
485
486
487 NTSTATUS FASTCALL
488 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
489 {
490 PTEXTOBJ TextObj;
491
492 TextObj = TEXTOBJ_AllocTextWithHandle();
493 if (!TextObj)
494 {
495 return STATUS_NO_MEMORY;
496 }
497
498 *NewFont = TextObj->BaseObject.hHmgr;
499 RtlCopyMemory(&TextObj->logfont.elfEnumLogfontEx.elfLogFont, lf, sizeof(LOGFONTW));
500 if (lf->lfEscapement != lf->lfOrientation)
501 {
502 /* this should really depend on whether GM_ADVANCED is set */
503 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation =
504 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement;
505 }
506 TEXTOBJ_UnlockText(TextObj);
507
508 return STATUS_SUCCESS;
509 }
510
511 /*************************************************************************
512 * TranslateCharsetInfo
513 *
514 * Fills a CHARSETINFO structure for a character set, code page, or
515 * font. This allows making the correspondance between different labelings
516 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
517 * of the same encoding.
518 *
519 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
520 * only one codepage should be set in *Src.
521 *
522 * RETURNS
523 * TRUE on success, FALSE on failure.
524 *
525 */
526 static BOOLEAN APIENTRY
527 IntTranslateCharsetInfo(PDWORD Src, /* [in]
528 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
529 if flags == TCI_SRCCHARSET: a character set value
530 if flags == TCI_SRCCODEPAGE: a code page value */
531 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
532 DWORD Flags /* [in] determines interpretation of lpSrc */)
533 {
534 int Index = 0;
535
536 switch (Flags)
537 {
538 case TCI_SRCFONTSIG:
539 while (0 == (*Src >> Index & 0x0001) && Index < MAXTCIINDEX)
540 {
541 Index++;
542 }
543 break;
544 case TCI_SRCCODEPAGE:
545 while ( *Src != FontTci[Index].ciACP && Index < MAXTCIINDEX)
546 {
547 Index++;
548 }
549 break;
550 case TCI_SRCCHARSET:
551 while ( *Src != FontTci[Index].ciCharset && Index < MAXTCIINDEX)
552 {
553 Index++;
554 }
555 break;
556 default:
557 return FALSE;
558 }
559
560 if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == FontTci[Index].ciCharset)
561 {
562 return FALSE;
563 }
564
565 RtlCopyMemory(Cs, &FontTci[Index], sizeof(CHARSETINFO));
566
567 return TRUE;
568 }
569
570
571 static void FASTCALL
572 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT_WinFNT_HeaderRec *pWin)
573 {
574 FT_Fixed XScale, YScale;
575 int Ascent, Descent;
576 FT_Face Face = FontGDI->face;
577
578 XScale = Face->size->metrics.x_scale;
579 YScale = Face->size->metrics.y_scale;
580
581 if (pWin)
582 {
583 TM->tmHeight = pWin->pixel_height;
584 TM->tmAscent = pWin->ascent;
585 TM->tmDescent = TM->tmHeight - TM->tmAscent;
586 TM->tmInternalLeading = pWin->internal_leading;
587 TM->tmExternalLeading = pWin->external_leading;
588 TM->tmAveCharWidth = pWin->avg_width;
589 TM->tmMaxCharWidth = pWin->max_width;
590 TM->tmWeight = pWin->weight;
591 TM->tmOverhang = 0;
592 TM->tmDigitizedAspectX = pWin->horizontal_resolution;
593 TM->tmDigitizedAspectY = pWin->vertical_resolution;
594 TM->tmFirstChar = pWin->first_char;
595 TM->tmLastChar = pWin->last_char;
596 TM->tmDefaultChar = pWin->default_char + pWin->first_char;
597 TM->tmBreakChar = pWin->break_char + pWin->first_char;
598 TM->tmItalic = pWin->italic;
599 TM->tmUnderlined = FontGDI->Underline;
600 TM->tmStruckOut = FontGDI->StrikeOut;
601 TM->tmPitchAndFamily = pWin->pitch_and_family;
602 TM->tmCharSet = pWin->charset;
603 return;
604 }
605
606 if (pOS2->usWinAscent + pOS2->usWinDescent == 0)
607 {
608 Ascent = pHori->Ascender;
609 Descent = -pHori->Descender;
610 }
611 else
612 {
613 Ascent = pOS2->usWinAscent;
614 Descent = pOS2->usWinDescent;
615 }
616
617 #if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */
618 TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
619 TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
620 #else /* This (ros) code was previously affected by a FreeType bug, but it works now */
621 TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
622 TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
623 #endif
624 TM->tmInternalLeading = (FT_MulFix(Ascent + Descent - Face->units_per_EM, YScale) + 32) >> 6;
625
626 TM->tmHeight = TM->tmAscent + TM->tmDescent;
627
628 /* MSDN says:
629 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
630 */
631 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
632 - ((Ascent + Descent)
633 - (pHori->Ascender - pHori->Descender)),
634 YScale) + 32) >> 6);
635
636 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
637 if (TM->tmAveCharWidth == 0)
638 {
639 TM->tmAveCharWidth = 1;
640 }
641
642 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
643 TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
644
645 TM->tmWeight = pOS2->usWeightClass;
646 TM->tmOverhang = 0;
647 TM->tmDigitizedAspectX = 96;
648 TM->tmDigitizedAspectY = 96;
649 TM->tmFirstChar = pOS2->usFirstCharIndex;
650 TM->tmDefaultChar = pOS2->usDefaultChar ? pOS2->usDefaultChar : 0xffff;
651 TM->tmLastChar = pOS2->usLastCharIndex;
652 TM->tmBreakChar = L'\0' != pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
653 TM->tmItalic = (Face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0;
654 TM->tmUnderlined = FontGDI->Underline;
655 TM->tmStruckOut = FontGDI->StrikeOut;
656
657 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
658 if (! FT_IS_FIXED_WIDTH(Face))
659 {
660 TM->tmPitchAndFamily = TMPF_FIXED_PITCH;
661 }
662 else
663 {
664 TM->tmPitchAndFamily = 0;
665 }
666
667 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
668 {
669 case PAN_FAMILY_SCRIPT:
670 TM->tmPitchAndFamily |= FF_SCRIPT;
671 break;
672 case PAN_FAMILY_DECORATIVE:
673 TM->tmPitchAndFamily |= FF_DECORATIVE;
674 break;
675
676 case PAN_ANY:
677 case PAN_NO_FIT:
678 case PAN_FAMILY_TEXT_DISPLAY:
679 case PAN_FAMILY_PICTORIAL: /* symbol fonts get treated as if they were text */
680 /* which is clearly not what the panose spec says. */
681 if (TM->tmPitchAndFamily == 0) /* fixed */
682 {
683 TM->tmPitchAndFamily = FF_MODERN;
684 }
685 else
686 {
687 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
688 {
689 case PAN_ANY:
690 case PAN_NO_FIT:
691 default:
692 TM->tmPitchAndFamily |= FF_DONTCARE;
693 break;
694
695 case PAN_SERIF_COVE:
696 case PAN_SERIF_OBTUSE_COVE:
697 case PAN_SERIF_SQUARE_COVE:
698 case PAN_SERIF_OBTUSE_SQUARE_COVE:
699 case PAN_SERIF_SQUARE:
700 case PAN_SERIF_THIN:
701 case PAN_SERIF_BONE:
702 case PAN_SERIF_EXAGGERATED:
703 case PAN_SERIF_TRIANGLE:
704 TM->tmPitchAndFamily |= FF_ROMAN;
705 break;
706
707 case PAN_SERIF_NORMAL_SANS:
708 case PAN_SERIF_OBTUSE_SANS:
709 case PAN_SERIF_PERP_SANS:
710 case PAN_SERIF_FLARED:
711 case PAN_SERIF_ROUNDED:
712 TM->tmPitchAndFamily |= FF_SWISS;
713 break;
714 }
715 }
716 break;
717 default:
718 TM->tmPitchAndFamily |= FF_DONTCARE;
719 }
720
721 if (FT_IS_SCALABLE(Face))
722 {
723 TM->tmPitchAndFamily |= TMPF_VECTOR;
724 }
725 if (FT_IS_SFNT(Face))
726 {
727 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
728 }
729
730 TM->tmCharSet = DEFAULT_CHARSET;
731 }
732
733 /*************************************************************
734 * IntGetOutlineTextMetrics
735 *
736 */
737 INT FASTCALL
738 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
739 UINT Size,
740 OUTLINETEXTMETRICW *Otm)
741 {
742 unsigned Needed;
743 TT_OS2 *pOS2;
744 TT_HoriHeader *pHori;
745 TT_Postscript *pPost;
746 FT_Fixed XScale, YScale;
747 ANSI_STRING FamilyNameA, StyleNameA;
748 UNICODE_STRING FamilyNameW, StyleNameW, Regular;
749 FT_WinFNT_HeaderRec Win;
750 FT_Error Error;
751 char *Cp;
752
753 Needed = sizeof(OUTLINETEXTMETRICW);
754
755 RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name);
756 RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
757
758 RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name);
759 RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
760
761 /* These names should be read from the TT name table */
762
763 /* length of otmpFamilyName */
764 Needed += FamilyNameW.Length + sizeof(WCHAR);
765
766 RtlInitUnicodeString(&Regular, L"regular");
767 /* length of otmpFaceName */
768 if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
769 {
770 Needed += FamilyNameW.Length + sizeof(WCHAR); /* just the family name */
771 }
772 else
773 {
774 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
775 }
776
777 /* length of otmpStyleName */
778 Needed += StyleNameW.Length + sizeof(WCHAR);
779
780 /* length of otmpFullName */
781 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
782
783 if (Size < Needed)
784 {
785 RtlFreeUnicodeString(&FamilyNameW);
786 RtlFreeUnicodeString(&StyleNameW);
787 return Needed;
788 }
789
790 XScale = FontGDI->face->size->metrics.x_scale;
791 YScale = FontGDI->face->size->metrics.y_scale;
792
793 IntLockFreeType;
794 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
795 if (NULL == pOS2)
796 {
797 IntUnLockFreeType;
798 DPRINT1("Can't find OS/2 table - not TT font?\n");
799 RtlFreeUnicodeString(&StyleNameW);
800 RtlFreeUnicodeString(&FamilyNameW);
801 return 0;
802 }
803
804 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
805 if (NULL == pHori)
806 {
807 IntUnLockFreeType;
808 DPRINT1("Can't find HHEA table - not TT font?\n");
809 RtlFreeUnicodeString(&StyleNameW);
810 RtlFreeUnicodeString(&FamilyNameW);
811 return 0;
812 }
813
814 pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* we can live with this failing */
815
816 Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
817
818 Otm->otmSize = Needed;
819
820 // FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
821 if (!(FontGDI->flRealizedType & FDM_TYPE_TEXT_METRIC))
822 {
823 FillTM(&FontGDI->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
824 FontGDI->flRealizedType |= FDM_TYPE_TEXT_METRIC;
825 }
826
827 RtlCopyMemory(&Otm->otmTextMetrics, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
828
829 Otm->otmFiller = 0;
830 RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
831 Otm->otmfsSelection = pOS2->fsSelection;
832 Otm->otmfsType = pOS2->fsType;
833 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
834 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
835 Otm->otmItalicAngle = 0; /* POST table */
836 Otm->otmEMSquare = FontGDI->face->units_per_EM;
837 Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
838 Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
839 Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
840 Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
841 Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
842 Otm->otmrcFontBox.left = (FT_MulFix(FontGDI->face->bbox.xMin, XScale) + 32) >> 6;
843 Otm->otmrcFontBox.right = (FT_MulFix(FontGDI->face->bbox.xMax, XScale) + 32) >> 6;
844 Otm->otmrcFontBox.top = (FT_MulFix(FontGDI->face->bbox.yMax, YScale) + 32) >> 6;
845 Otm->otmrcFontBox.bottom = (FT_MulFix(FontGDI->face->bbox.yMin, YScale) + 32) >> 6;
846 Otm->otmMacAscent = FontGDI->TextMetric.tmAscent;
847 Otm->otmMacDescent = -FontGDI->TextMetric.tmDescent;
848 Otm->otmMacLineGap = Otm->otmLineGap;
849 Otm->otmusMinimumPPEM = 0; /* TT Header */
850 Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
851 Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
852 Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
853 Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
854 Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
855 Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
856 Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
857 Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
858 Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
859 Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
860 if (!pPost)
861 {
862 Otm->otmsUnderscoreSize = 0;
863 Otm->otmsUnderscorePosition = 0;
864 }
865 else
866 {
867 Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
868 Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
869 }
870
871 IntUnLockFreeType;
872
873 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
874 Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
875 Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
876 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
877 Cp += FamilyNameW.Length + sizeof(WCHAR);
878 Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
879 wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
880 Cp += StyleNameW.Length + sizeof(WCHAR);
881 Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
882 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
883 if (0 != RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
884 {
885 wcscat((WCHAR*) Cp, L" ");
886 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
887 Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
888 }
889 else
890 {
891 Cp += FamilyNameW.Length + sizeof(WCHAR);
892 }
893 Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
894 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
895 wcscat((WCHAR*) Cp, L" ");
896 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
897
898 RtlFreeUnicodeString(&StyleNameW);
899 RtlFreeUnicodeString(&FamilyNameW);
900
901 return Needed;
902 }
903
904 static PFONTGDI FASTCALL
905 FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
906 {
907 PLIST_ENTRY Entry;
908 PFONT_ENTRY CurrentEntry;
909 ANSI_STRING EntryFaceNameA;
910 UNICODE_STRING EntryFaceNameW;
911 FONTGDI *FontGDI;
912
913 Entry = Head->Flink;
914 while (Entry != Head)
915 {
916 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
917
918 FontGDI = CurrentEntry->Font;
919 ASSERT(FontGDI);
920
921 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
922 RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
923 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
924 {
925 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
926 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
927 }
928
929 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
930 {
931 RtlFreeUnicodeString(&EntryFaceNameW);
932 return FontGDI;
933 }
934
935 RtlFreeUnicodeString(&EntryFaceNameW);
936 Entry = Entry->Flink;
937 }
938
939 return NULL;
940 }
941
942 static PFONTGDI FASTCALL
943 FindFaceNameInLists(PUNICODE_STRING FaceName)
944 {
945 PW32PROCESS Win32Process;
946 PFONTGDI Font;
947
948 /* Search the process local list */
949 Win32Process = PsGetCurrentProcessWin32Process();
950 IntLockProcessPrivateFonts(Win32Process);
951 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
952 IntUnLockProcessPrivateFonts(Win32Process);
953 if (NULL != Font)
954 {
955 return Font;
956 }
957
958 /* Search the global list */
959 IntLockGlobalFonts;
960 Font = FindFaceNameInList(FaceName, &FontListHead);
961 IntUnLockGlobalFonts;
962
963 return Font;
964 }
965
966 static void FASTCALL
967 FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
968 {
969 ANSI_STRING StyleA;
970 UNICODE_STRING StyleW;
971 TT_OS2 *pOS2;
972 FONTSIGNATURE fs;
973 CHARSETINFO CharSetInfo;
974 unsigned i, Size;
975 OUTLINETEXTMETRICW *Otm;
976 LOGFONTW *Lf;
977 TEXTMETRICW *TM;
978 NEWTEXTMETRICW *Ntm;
979 DWORD fs0;
980
981 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
982 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
983 Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
984 if (!Otm)
985 {
986 return;
987 }
988 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
989
990 Lf = &Info->EnumLogFontEx.elfLogFont;
991 TM = &Otm->otmTextMetrics;
992
993 Lf->lfHeight = TM->tmHeight;
994 Lf->lfWidth = TM->tmAveCharWidth;
995 Lf->lfWeight = TM->tmWeight;
996 Lf->lfItalic = TM->tmItalic;
997 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
998 Lf->lfCharSet = TM->tmCharSet;
999 Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
1000 Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
1001 Lf->lfQuality = PROOF_QUALITY;
1002
1003 Ntm = &Info->NewTextMetricEx.ntmTm;
1004 Ntm->tmHeight = TM->tmHeight;
1005 Ntm->tmAscent = TM->tmAscent;
1006 Ntm->tmDescent = TM->tmDescent;
1007 Ntm->tmInternalLeading = TM->tmInternalLeading;
1008 Ntm->tmExternalLeading = TM->tmExternalLeading;
1009 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
1010 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
1011 Ntm->tmWeight = TM->tmWeight;
1012 Ntm->tmOverhang = TM->tmOverhang;
1013 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
1014 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
1015 Ntm->tmFirstChar = TM->tmFirstChar;
1016 Ntm->tmLastChar = TM->tmLastChar;
1017 Ntm->tmDefaultChar = TM->tmDefaultChar;
1018 Ntm->tmBreakChar = TM->tmBreakChar;
1019 Ntm->tmItalic = TM->tmItalic;
1020 Ntm->tmUnderlined = TM->tmUnderlined;
1021 Ntm->tmStruckOut = TM->tmStruckOut;
1022 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
1023 Ntm->tmCharSet = TM->tmCharSet;
1024 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
1025
1026 if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
1027
1028 if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
1029
1030 Ntm->ntmSizeEM = Otm->otmEMSquare;
1031 Ntm->ntmCellHeight = 0;
1032 Ntm->ntmAvgWidth = 0;
1033
1034 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
1035 ? TRUETYPE_FONTTYPE : 0);
1036
1037 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
1038 Info->FontType |= RASTER_FONTTYPE;
1039
1040 ExFreePoolWithTag(Otm, TAG_GDITEXT);
1041
1042 wcsncpy(Info->EnumLogFontEx.elfLogFont.lfFaceName, FaceName, LF_FACESIZE);
1043 wcsncpy(Info->EnumLogFontEx.elfFullName, FaceName, LF_FULLFACESIZE);
1044 RtlInitAnsiString(&StyleA, FontGDI->face->style_name);
1045 RtlAnsiStringToUnicodeString(&StyleW, &StyleA, TRUE);
1046 wcsncpy(Info->EnumLogFontEx.elfStyle, StyleW.Buffer, LF_FACESIZE);
1047 RtlFreeUnicodeString(&StyleW);
1048
1049 Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
1050 Info->EnumLogFontEx.elfScript[0] = L'\0';
1051 IntLockFreeType;
1052 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
1053 IntUnLockFreeType;
1054 if (NULL != pOS2)
1055 {
1056 fs.fsCsb[0] = pOS2->ulCodePageRange1;
1057 fs.fsCsb[1] = pOS2->ulCodePageRange2;
1058 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
1059 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
1060 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
1061 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
1062
1063 if (0 == pOS2->version)
1064 {
1065 FT_UInt Dummy;
1066
1067 if (FT_Get_First_Char(FontGDI->face, &Dummy) < 0x100)
1068 fs.fsCsb[0] |= FS_LATIN1;
1069 else
1070 fs.fsCsb[0] |= FS_SYMBOL;
1071 }
1072 if (fs.fsCsb[0] == 0)
1073 { /* let's see if we can find any interesting cmaps */
1074 for (i = 0; i < FontGDI->face->num_charmaps; i++)
1075 {
1076 switch (FontGDI->face->charmaps[i]->encoding)
1077 {
1078 case FT_ENCODING_UNICODE:
1079 case FT_ENCODING_APPLE_ROMAN:
1080 fs.fsCsb[0] |= FS_LATIN1;
1081 break;
1082 case FT_ENCODING_MS_SYMBOL:
1083 fs.fsCsb[0] |= FS_SYMBOL;
1084 break;
1085 default:
1086 break;
1087 }
1088 }
1089 }
1090 for (i = 0; i < MAXTCIINDEX; i++)
1091 {
1092 fs0 = 1L << i;
1093 if (fs.fsCsb[0] & fs0)
1094 {
1095 if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
1096 {
1097 CharSetInfo.ciCharset = DEFAULT_CHARSET;
1098 }
1099 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
1100 {
1101 Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
1102 if (NULL != ElfScripts[i])
1103 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
1104 else
1105 {
1106 DPRINT1("Unknown elfscript for bit %d\n", i);
1107 }
1108 }
1109 }
1110 }
1111 Info->NewTextMetricEx.ntmFontSig = fs;
1112 }
1113 }
1114
1115 static int FASTCALL
1116 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
1117 {
1118 DWORD i;
1119 UNICODE_STRING InfoFaceName;
1120
1121 for (i = 0; i < InfoEntries; i++)
1122 {
1123 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
1124 if (0 == RtlCompareUnicodeString(&InfoFaceName, FaceName, TRUE))
1125 {
1126 return i;
1127 }
1128 }
1129
1130 return -1;
1131 }
1132
1133 static BOOLEAN FASTCALL
1134 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
1135 PFONTFAMILYINFO Info, DWORD InfoEntries)
1136 {
1137 UNICODE_STRING LogFontFaceName;
1138
1139 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
1140 if (0 != LogFontFaceName.Length
1141 && 0 != RtlCompareUnicodeString(&LogFontFaceName, FaceName, TRUE))
1142 {
1143 return FALSE;
1144 }
1145
1146 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
1147 }
1148
1149 static BOOLEAN FASTCALL
1150 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
1151 PFONTFAMILYINFO Info,
1152 DWORD *Count,
1153 DWORD Size,
1154 PLIST_ENTRY Head)
1155 {
1156 PLIST_ENTRY Entry;
1157 PFONT_ENTRY CurrentEntry;
1158 ANSI_STRING EntryFaceNameA;
1159 UNICODE_STRING EntryFaceNameW;
1160 FONTGDI *FontGDI;
1161
1162 Entry = Head->Flink;
1163 while (Entry != Head)
1164 {
1165 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1166
1167 FontGDI = CurrentEntry->Font;
1168 ASSERT(FontGDI);
1169
1170 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
1171 RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
1172 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
1173 {
1174 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
1175 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
1176 }
1177
1178 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
1179 {
1180 if (*Count < Size)
1181 {
1182 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
1183 }
1184 (*Count)++;
1185 }
1186 RtlFreeUnicodeString(&EntryFaceNameW);
1187 Entry = Entry->Flink;
1188 }
1189
1190 return TRUE;
1191 }
1192
1193 typedef struct FontFamilyInfoCallbackContext
1194 {
1195 LPLOGFONTW LogFont;
1196 PFONTFAMILYINFO Info;
1197 DWORD Count;
1198 DWORD Size;
1199 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
1200
1201 static NTSTATUS APIENTRY
1202 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
1203 IN PVOID ValueData, IN ULONG ValueLength,
1204 IN PVOID Context, IN PVOID EntryContext)
1205 {
1206 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
1207 UNICODE_STRING RegistryName, RegistryValue;
1208 int Existing;
1209 PFONTGDI FontGDI;
1210
1211 if (REG_SZ != ValueType)
1212 {
1213 return STATUS_SUCCESS;
1214 }
1215 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
1216 RtlInitUnicodeString(&RegistryName, ValueName);
1217
1218 /* Do we need to include this font family? */
1219 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
1220 min(InfoContext->Count, InfoContext->Size)))
1221 {
1222 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
1223 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
1224 min(InfoContext->Count, InfoContext->Size));
1225 if (0 <= Existing)
1226 {
1227 /* We already have the information about the "real" font. Just copy it */
1228 if (InfoContext->Count < InfoContext->Size)
1229 {
1230 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
1231 wcsncpy(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
1232 RegistryName.Buffer, LF_FACESIZE);
1233 }
1234 InfoContext->Count++;
1235 return STATUS_SUCCESS;
1236 }
1237
1238 /* Try to find information about the "real" font */
1239 FontGDI = FindFaceNameInLists(&RegistryValue);
1240 if (NULL == FontGDI)
1241 {
1242 /* "Real" font not found, discard this registry entry */
1243 return STATUS_SUCCESS;
1244 }
1245
1246 /* Return info about the "real" font but with the name of the alias */
1247 if (InfoContext->Count < InfoContext->Size)
1248 {
1249 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
1250 RegistryName.Buffer, FontGDI);
1251 }
1252 InfoContext->Count++;
1253 return STATUS_SUCCESS;
1254 }
1255
1256 return STATUS_SUCCESS;
1257 }
1258
1259 static BOOLEAN FASTCALL
1260 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
1261 PFONTFAMILYINFO Info,
1262 DWORD *Count,
1263 DWORD Size)
1264 {
1265 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
1266 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
1267 NTSTATUS Status;
1268
1269 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\SysFontSubstitutes
1270 The real work is done in the registry callback function */
1271 Context.LogFont = LogFont;
1272 Context.Info = Info;
1273 Context.Count = *Count;
1274 Context.Size = Size;
1275
1276 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
1277 QueryTable[0].Flags = 0;
1278 QueryTable[0].Name = NULL;
1279 QueryTable[0].EntryContext = NULL;
1280 QueryTable[0].DefaultType = REG_NONE;
1281 QueryTable[0].DefaultData = NULL;
1282 QueryTable[0].DefaultLength = 0;
1283
1284 QueryTable[1].QueryRoutine = NULL;
1285 QueryTable[1].Name = NULL;
1286
1287 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
1288 L"SysFontSubstitutes",
1289 QueryTable,
1290 &Context,
1291 NULL);
1292 if (NT_SUCCESS(Status))
1293 {
1294 *Count = Context.Count;
1295 }
1296
1297 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
1298 }
1299
1300 BOOL
1301 FASTCALL
1302 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
1303 {
1304 if ( lprs )
1305 {
1306 lprs->nSize = sizeof(RASTERIZER_STATUS);
1307 lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
1308 lprs->nLanguageID = gusLanguageID;
1309 return TRUE;
1310 }
1311 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1312 return FALSE;
1313 }
1314
1315
1316 FT_Glyph APIENTRY
1317 ftGdiGlyphCacheGet(
1318 FT_Face Face,
1319 INT GlyphIndex,
1320 INT Height)
1321 {
1322 PLIST_ENTRY CurrentEntry;
1323 PFONT_CACHE_ENTRY FontEntry;
1324
1325 // DbgPrint("CacheGet\n");
1326
1327 CurrentEntry = FontCacheListHead.Flink;
1328 while (CurrentEntry != &FontCacheListHead)
1329 {
1330 FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
1331 if (FontEntry->Face == Face &&
1332 FontEntry->GlyphIndex == GlyphIndex &&
1333 FontEntry->Height == Height)
1334 break;
1335 CurrentEntry = CurrentEntry->Flink;
1336 }
1337
1338 if (CurrentEntry == &FontCacheListHead)
1339 {
1340 // DbgPrint("Miss! %x\n", FontEntry->Glyph);
1341 /*
1342 Misses++;
1343 if (Misses>100) {
1344 DbgPrint ("Hits: %d Misses: %d\n", Hits, Misses);
1345 Hits = Misses = 0;
1346 }
1347 */
1348 return NULL;
1349 }
1350
1351 RemoveEntryList(CurrentEntry);
1352 InsertHeadList(&FontCacheListHead, CurrentEntry);
1353
1354 // DbgPrint("Hit! %x\n", FontEntry->Glyph);
1355 /*
1356 Hits++;
1357
1358 if (Hits>100) {
1359 DbgPrint ("Hits: %d Misses: %d\n", Hits, Misses);
1360 Hits = Misses = 0;
1361 }
1362 */
1363 return FontEntry->Glyph;
1364 }
1365
1366 FT_Glyph APIENTRY
1367 ftGdiGlyphCacheSet(
1368 FT_Face Face,
1369 INT GlyphIndex,
1370 INT Height,
1371 FT_GlyphSlot GlyphSlot,
1372 FT_Render_Mode RenderMode)
1373 {
1374 FT_Glyph GlyphCopy;
1375 INT error;
1376 PFONT_CACHE_ENTRY NewEntry;
1377
1378 // DbgPrint("CacheSet.\n");
1379
1380 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
1381 if (error)
1382 {
1383 DbgPrint("Failure caching glyph.\n");
1384 return NULL;
1385 };
1386 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
1387 if (error)
1388 {
1389 DbgPrint("Failure rendering glyph.\n");
1390 return NULL;
1391 };
1392
1393 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
1394 if (!NewEntry)
1395 {
1396 DbgPrint("Alloc failure caching glyph.\n");
1397 FT_Done_Glyph(GlyphCopy);
1398 return NULL;
1399 }
1400
1401 NewEntry->GlyphIndex = GlyphIndex;
1402 NewEntry->Face = Face;
1403 NewEntry->Glyph = GlyphCopy;
1404 NewEntry->Height = Height;
1405
1406 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
1407 if (FontCacheNumEntries++ > MAX_FONT_CACHE)
1408 {
1409 NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
1410 FT_Done_Glyph(NewEntry->Glyph);
1411 RemoveTailList(&FontCacheListHead);
1412 ExFreePool(NewEntry);
1413 FontCacheNumEntries--;
1414 }
1415
1416 // DbgPrint("Returning the glyphcopy: %x\n", GlyphCopy);
1417
1418 return GlyphCopy;
1419 }
1420
1421
1422 static
1423 void
1424 FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
1425 {
1426 pt->x.value = vec->x >> 6;
1427 pt->x.fract = (vec->x & 0x3f) << 10;
1428 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
1429 pt->y.value = vec->y >> 6;
1430 pt->y.fract = (vec->y & 0x3f) << 10;
1431 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
1432 return;
1433 }
1434
1435 /*
1436 This function builds an FT_Fixed from a float. It puts the integer part
1437 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
1438 It fails if the integer part of the float number is greater than SHORT_MAX.
1439 */
1440 static __inline FT_Fixed FT_FixedFromFloat(float f)
1441 {
1442 short value = f;
1443 unsigned short fract = (f - value) * 0xFFFF;
1444 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
1445 }
1446
1447 /*
1448 This function builds an FT_Fixed from a FIXED. It simply put f.value
1449 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
1450 */
1451 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
1452 {
1453 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
1454 }
1455
1456 /*
1457 * Based on WineEngGetGlyphOutline
1458 *
1459 */
1460 ULONG
1461 FASTCALL
1462 ftGdiGetGlyphOutline(
1463 PDC dc,
1464 WCHAR wch,
1465 UINT iFormat,
1466 LPGLYPHMETRICS pgm,
1467 ULONG cjBuf,
1468 PVOID pvBuf,
1469 LPMAT2 pmat2,
1470 BOOL bIgnoreRotation)
1471 {
1472 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
1473 PDC_ATTR Dc_Attr;
1474 PTEXTOBJ TextObj;
1475 PFONTGDI FontGDI;
1476 HFONT hFont = 0;
1477 GLYPHMETRICS gm;
1478 ULONG Size;
1479 FT_Face ft_face;
1480 FT_UInt glyph_index;
1481 DWORD width, height, pitch, needed = 0;
1482 FT_Bitmap ft_bitmap;
1483 FT_Error error;
1484 INT left, right, top = 0, bottom = 0;
1485 FT_Angle angle = 0;
1486 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
1487 FLOAT eM11, widthRatio = 1.0;
1488 FT_Matrix transMat = identityMat;
1489 BOOL needsTransform = FALSE;
1490 INT orientation;
1491 LONG aveWidth;
1492 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
1493 OUTLINETEXTMETRICW *potm;
1494 int n = 0;
1495 FT_CharMap found = 0, charmap;
1496 XFORM xForm;
1497
1498 DPRINT("%d, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
1499 cjBuf, pvBuf, pmat2);
1500
1501 Dc_Attr = dc->pDc_Attr;
1502 if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
1503
1504 MatrixS2XForm(&xForm, &dc->DcLevel.mxWorldToDevice);
1505 eM11 = xForm.eM11;
1506
1507 hFont = Dc_Attr->hlfntNew;
1508 TextObj = RealizeFontInit(hFont);
1509
1510 if (!TextObj)
1511 {
1512 SetLastWin32Error(ERROR_INVALID_HANDLE);
1513 return GDI_ERROR;
1514 }
1515 FontGDI = ObjToGDI(TextObj->Font, FONT);
1516 ft_face = FontGDI->face;
1517
1518 aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth: 0;
1519 orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation: 0;
1520
1521 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
1522 potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
1523 if (!potm)
1524 {
1525 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1526 TEXTOBJ_UnlockText(TextObj);
1527 return GDI_ERROR;
1528 }
1529 IntGetOutlineTextMetrics(FontGDI, Size, potm);
1530
1531 IntLockFreeType;
1532
1533 /* During testing, I never saw this used. In here just incase.*/
1534 if (ft_face->charmap == NULL)
1535 {
1536 DPRINT("WARNING: No charmap selected!\n");
1537 DPRINT("This font face has %d charmaps\n", ft_face->num_charmaps);
1538
1539 for (n = 0; n < ft_face->num_charmaps; n++)
1540 {
1541 charmap = ft_face->charmaps[n];
1542 DPRINT("found charmap encoding: %u\n", charmap->encoding);
1543 if (charmap->encoding != 0)
1544 {
1545 found = charmap;
1546 break;
1547 }
1548 }
1549 if (!found)
1550 {
1551 DPRINT1("WARNING: Could not find desired charmap!\n");
1552 }
1553 error = FT_Set_Charmap(ft_face, found);
1554 if (error)
1555 {
1556 DPRINT1("WARNING: Could not set the charmap!\n");
1557 }
1558 }
1559
1560 // FT_Set_Pixel_Sizes(ft_face,
1561 // TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
1562 /* FIXME should set character height if neg */
1563 // (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
1564 // TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
1565
1566 TEXTOBJ_UnlockText(TextObj);
1567
1568 if (iFormat & GGO_GLYPH_INDEX)
1569 {
1570 glyph_index = wch;
1571 iFormat &= ~GGO_GLYPH_INDEX;
1572 }
1573 else glyph_index = FT_Get_Char_Index(ft_face, wch);
1574
1575 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
1576 load_flags |= FT_LOAD_NO_BITMAP;
1577
1578 if (iFormat & GGO_UNHINTED)
1579 {
1580 load_flags |= FT_LOAD_NO_HINTING;
1581 iFormat &= ~GGO_UNHINTED;
1582 }
1583
1584 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
1585 if (error)
1586 {
1587 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1588 IntUnLockFreeType;
1589 if (potm) ExFreePoolWithTag(potm, TAG_GDITEXT);
1590 return GDI_ERROR;
1591 }
1592 IntUnLockFreeType;
1593
1594 if (aveWidth && potm)
1595 {
1596 widthRatio = (FLOAT)aveWidth * eM11 /
1597 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
1598 }
1599
1600 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
1601 right = (INT)((ft_face->glyph->metrics.horiBearingX +
1602 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
1603
1604 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
1605 lsb = left >> 6;
1606 bbx = (right - left) >> 6;
1607
1608 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
1609
1610 IntLockFreeType;
1611
1612 /* Scaling transform */
1613 if (aveWidth)
1614 {
1615 FT_Matrix scaleMat;
1616 DPRINT("Scaling Trans!\n");
1617 scaleMat.xx = FT_FixedFromFloat(widthRatio);
1618 scaleMat.xy = 0;
1619 scaleMat.yx = 0;
1620 scaleMat.yy = (1 << 16);
1621 FT_Matrix_Multiply(&scaleMat, &transMat);
1622 needsTransform = TRUE;
1623 }
1624
1625 /* Slant transform */
1626 if (potm->otmTextMetrics.tmItalic)
1627 {
1628 FT_Matrix slantMat;
1629 DPRINT("Slant Trans!\n");
1630 slantMat.xx = (1 << 16);
1631 slantMat.xy = ((1 << 16) >> 2);
1632 slantMat.yx = 0;
1633 slantMat.yy = (1 << 16);
1634 FT_Matrix_Multiply(&slantMat, &transMat);
1635 needsTransform = TRUE;
1636 }
1637
1638 /* Rotation transform */
1639 if (orientation)
1640 {
1641 FT_Matrix rotationMat;
1642 FT_Vector vecAngle;
1643 DPRINT("Rotation Trans!\n");
1644 angle = FT_FixedFromFloat((float)orientation / 10.0);
1645 FT_Vector_Unit(&vecAngle, angle);
1646 rotationMat.xx = vecAngle.x;
1647 rotationMat.xy = -vecAngle.y;
1648 rotationMat.yx = -rotationMat.xy;
1649 rotationMat.yy = rotationMat.xx;
1650 FT_Matrix_Multiply(&rotationMat, &transMat);
1651 needsTransform = TRUE;
1652 }
1653
1654 /* Extra transformation specified by caller */
1655 if (pmat2)
1656 {
1657 FT_Matrix extraMat;
1658 DPRINT("MAT2 Matrix Trans!\n");
1659 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
1660 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
1661 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
1662 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
1663 FT_Matrix_Multiply(&extraMat, &transMat);
1664 needsTransform = TRUE;
1665 }
1666
1667 if (potm) ExFreePoolWithTag(potm, TAG_GDITEXT); /* It looks like we are finished with potm ATM.*/
1668
1669 if (!needsTransform)
1670 {
1671 DPRINT("No Need to be Transformed!\n");
1672 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
1673 bottom = (ft_face->glyph->metrics.horiBearingY -
1674 ft_face->glyph->metrics.height) & -64;
1675 gm.gmCellIncX = adv;
1676 gm.gmCellIncY = 0;
1677 }
1678 else
1679 {
1680 INT xc, yc;
1681 FT_Vector vec;
1682 for (xc = 0; xc < 2; xc++)
1683 {
1684 for (yc = 0; yc < 2; yc++)
1685 {
1686 vec.x = (ft_face->glyph->metrics.horiBearingX +
1687 xc * ft_face->glyph->metrics.width);
1688 vec.y = ft_face->glyph->metrics.horiBearingY -
1689 yc * ft_face->glyph->metrics.height;
1690 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
1691 FT_Vector_Transform(&vec, &transMat);
1692 if (xc == 0 && yc == 0)
1693 {
1694 left = right = vec.x;
1695 top = bottom = vec.y;
1696 }
1697 else
1698 {
1699 if (vec.x < left) left = vec.x;
1700 else if (vec.x > right) right = vec.x;
1701 if (vec.y < bottom) bottom = vec.y;
1702 else if (vec.y > top) top = vec.y;
1703 }
1704 }
1705 }
1706 left = left & -64;
1707 right = (right + 63) & -64;
1708 bottom = bottom & -64;
1709 top = (top + 63) & -64;
1710
1711 DPRINT("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
1712 vec.x = ft_face->glyph->metrics.horiAdvance;
1713 vec.y = 0;
1714 FT_Vector_Transform(&vec, &transMat);
1715 gm.gmCellIncX = (vec.x+63) >> 6;
1716 gm.gmCellIncY = -((vec.y+63) >> 6);
1717 }
1718 gm.gmBlackBoxX = (right - left) >> 6;
1719 gm.gmBlackBoxY = (top - bottom) >> 6;
1720 gm.gmptGlyphOrigin.x = left >> 6;
1721 gm.gmptGlyphOrigin.y = top >> 6;
1722
1723 DPRINT("CX %d CY %d BBX %d BBY %d GOX %d GOY %d\n",
1724 gm.gmCellIncX, gm.gmCellIncY,
1725 gm.gmBlackBoxX, gm.gmBlackBoxY,
1726 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
1727
1728 IntUnLockFreeType;
1729
1730 if (pgm) RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
1731
1732 if (iFormat == GGO_METRICS)
1733 {
1734 DPRINT("GGO_METRICS Exit!\n");
1735 return 1; /* FIXME */
1736 }
1737
1738 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
1739 {
1740 DPRINT1("loaded a bitmap\n");
1741 return GDI_ERROR;
1742 }
1743
1744 switch (iFormat)
1745 {
1746 case GGO_BITMAP:
1747 width = gm.gmBlackBoxX;
1748 height = gm.gmBlackBoxY;
1749 pitch = ((width + 31) >> 5) << 2;
1750 needed = pitch * height;
1751
1752 if (!pvBuf || !cjBuf) break;
1753
1754 switch (ft_face->glyph->format)
1755 {
1756 case ft_glyph_format_bitmap:
1757 {
1758 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
1759 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
1760 INT h = ft_face->glyph->bitmap.rows;
1761 while (h--)
1762 {
1763 RtlCopyMemory(dst, src, w);
1764 src += ft_face->glyph->bitmap.pitch;
1765 dst += pitch;
1766 }
1767 break;
1768 }
1769
1770 case ft_glyph_format_outline:
1771 ft_bitmap.width = width;
1772 ft_bitmap.rows = height;
1773 ft_bitmap.pitch = pitch;
1774 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
1775 ft_bitmap.buffer = pvBuf;
1776
1777 IntLockFreeType;
1778 if (needsTransform)
1779 {
1780 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1781 }
1782 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1783 /* Note: FreeType will only set 'black' bits for us. */
1784 RtlZeroMemory(pvBuf, needed);
1785 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1786 IntUnLockFreeType;
1787 break;
1788
1789 default:
1790 DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
1791 return GDI_ERROR;
1792 }
1793 break;
1794
1795 case GGO_GRAY2_BITMAP:
1796 case GGO_GRAY4_BITMAP:
1797 case GGO_GRAY8_BITMAP:
1798 {
1799 unsigned int mult, row, col;
1800 BYTE *start, *ptr;
1801
1802 width = gm.gmBlackBoxX;
1803 height = gm.gmBlackBoxY;
1804 pitch = (width + 3) / 4 * 4;
1805 needed = pitch * height;
1806
1807 if (!pvBuf || !cjBuf) break;
1808
1809 switch (ft_face->glyph->format)
1810 {
1811 case ft_glyph_format_bitmap:
1812 {
1813 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
1814 INT h = ft_face->glyph->bitmap.rows;
1815 INT x;
1816 while (h--)
1817 {
1818 for (x = 0; x < pitch; x++)
1819 {
1820 if (x < ft_face->glyph->bitmap.width)
1821 dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
1822 else
1823 dst[x] = 0;
1824 }
1825 src += ft_face->glyph->bitmap.pitch;
1826 dst += pitch;
1827 }
1828 return needed;
1829 }
1830 case ft_glyph_format_outline:
1831 {
1832 ft_bitmap.width = width;
1833 ft_bitmap.rows = height;
1834 ft_bitmap.pitch = pitch;
1835 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
1836 ft_bitmap.buffer = pvBuf;
1837
1838 IntLockFreeType;
1839 if (needsTransform)
1840 {
1841 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
1842 }
1843 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
1844 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
1845 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
1846 IntUnLockFreeType;
1847
1848 if (iFormat == GGO_GRAY2_BITMAP)
1849 mult = 4;
1850 else if (iFormat == GGO_GRAY4_BITMAP)
1851 mult = 16;
1852 else if (iFormat == GGO_GRAY8_BITMAP)
1853 mult = 64;
1854 else
1855 {
1856 return GDI_ERROR;
1857 }
1858 }
1859 default:
1860 DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
1861 return GDI_ERROR;
1862 }
1863 start = pvBuf;
1864 for (row = 0; row < height; row++)
1865 {
1866 ptr = start;
1867 for (col = 0; col < width; col++, ptr++)
1868 {
1869 *ptr = (((int)*ptr) * mult + 128) / 256;
1870 }
1871 start += pitch;
1872 }
1873 break;
1874 }
1875
1876 case GGO_NATIVE:
1877 {
1878 int contour, point = 0, first_pt;
1879 FT_Outline *outline = &ft_face->glyph->outline;
1880 TTPOLYGONHEADER *pph;
1881 TTPOLYCURVE *ppc;
1882 DWORD pph_start, cpfx, type;
1883
1884 if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
1885
1886 IntLockFreeType;
1887 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
1888
1889 for (contour = 0; contour < outline->n_contours; contour++)
1890 {
1891 pph_start = needed;
1892 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
1893 first_pt = point;
1894 if (pvBuf)
1895 {
1896 pph->dwType = TT_POLYGON_TYPE;
1897 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1898 }
1899 needed += sizeof(*pph);
1900 point++;
1901 while (point <= outline->contours[contour])
1902 {
1903 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
1904 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1905 TT_PRIM_LINE : TT_PRIM_QSPLINE;
1906 cpfx = 0;
1907 do
1908 {
1909 if (pvBuf)
1910 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1911 cpfx++;
1912 point++;
1913 }
1914 while (point <= outline->contours[contour] &&
1915 (outline->tags[point] & FT_Curve_Tag_On) ==
1916 (outline->tags[point-1] & FT_Curve_Tag_On));
1917
1918 /* At the end of a contour Windows adds the start point, but
1919 only for Beziers */
1920 if (point > outline->contours[contour] &&
1921 !(outline->tags[point-1] & FT_Curve_Tag_On))
1922 {
1923 if (pvBuf)
1924 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
1925 cpfx++;
1926 }
1927 else if (point <= outline->contours[contour] &&
1928 outline->tags[point] & FT_Curve_Tag_On)
1929 {
1930 /* add closing pt for bezier */
1931 if (pvBuf)
1932 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
1933 cpfx++;
1934 point++;
1935 }
1936 if (pvBuf)
1937 {
1938 ppc->wType = type;
1939 ppc->cpfx = cpfx;
1940 }
1941 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
1942 }
1943 if (pvBuf) pph->cb = needed - pph_start;
1944 }
1945 IntUnLockFreeType;
1946 break;
1947 }
1948 case GGO_BEZIER:
1949 {
1950 /* Convert the quadratic Beziers to cubic Beziers.
1951 The parametric eqn for a cubic Bezier is, from PLRM:
1952 r(t) = at^3 + bt^2 + ct + r0
1953 with the control points:
1954 r1 = r0 + c/3
1955 r2 = r1 + (c + b)/3
1956 r3 = r0 + c + b + a
1957
1958 A quadratic Beizer has the form:
1959 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
1960
1961 So equating powers of t leads to:
1962 r1 = 2/3 p1 + 1/3 p0
1963 r2 = 2/3 p1 + 1/3 p2
1964 and of course r0 = p0, r3 = p2
1965 */
1966
1967 int contour, point = 0, first_pt;
1968 FT_Outline *outline = &ft_face->glyph->outline;
1969 TTPOLYGONHEADER *pph;
1970 TTPOLYCURVE *ppc;
1971 DWORD pph_start, cpfx, type;
1972 FT_Vector cubic_control[4];
1973 if (cjBuf == 0) pvBuf = NULL;
1974
1975 if (needsTransform && pvBuf)
1976 {
1977 IntLockFreeType;
1978 FT_Outline_Transform(outline, &transMat);
1979 IntUnLockFreeType;
1980 }
1981
1982 for (contour = 0; contour < outline->n_contours; contour++)
1983 {
1984 pph_start = needed;
1985 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
1986 first_pt = point;
1987 if (pvBuf)
1988 {
1989 pph->dwType = TT_POLYGON_TYPE;
1990 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
1991 }
1992 needed += sizeof(*pph);
1993 point++;
1994 while (point <= outline->contours[contour])
1995 {
1996 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
1997 type = (outline->tags[point] & FT_Curve_Tag_On) ?
1998 TT_PRIM_LINE : TT_PRIM_CSPLINE;
1999 cpfx = 0;
2000 do
2001 {
2002 if (type == TT_PRIM_LINE)
2003 {
2004 if (pvBuf)
2005 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2006 cpfx++;
2007 point++;
2008 }
2009 else
2010 {
2011 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2012 so cpfx = 3n */
2013
2014 /* FIXME: Possible optimization in endpoint calculation
2015 if there are two consecutive curves */
2016 cubic_control[0] = outline->points[point-1];
2017 if (!(outline->tags[point-1] & FT_Curve_Tag_On))
2018 {
2019 cubic_control[0].x += outline->points[point].x + 1;
2020 cubic_control[0].y += outline->points[point].y + 1;
2021 cubic_control[0].x >>= 1;
2022 cubic_control[0].y >>= 1;
2023 }
2024 if (point+1 > outline->contours[contour])
2025 cubic_control[3] = outline->points[first_pt];
2026 else
2027 {
2028 cubic_control[3] = outline->points[point+1];
2029 if (!(outline->tags[point+1] & FT_Curve_Tag_On))
2030 {
2031 cubic_control[3].x += outline->points[point].x + 1;
2032 cubic_control[3].y += outline->points[point].y + 1;
2033 cubic_control[3].x >>= 1;
2034 cubic_control[3].y >>= 1;
2035 }
2036 }
2037 /* r1 = 1/3 p0 + 2/3 p1
2038 r2 = 1/3 p2 + 2/3 p1 */
2039 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2040 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2041 cubic_control[2] = cubic_control[1];
2042 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2043 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2044 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2045 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2046 if (pvBuf)
2047 {
2048 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2049 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2050 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2051 }
2052 cpfx += 3;
2053 point++;
2054 }
2055 }
2056 while (point <= outline->contours[contour] &&
2057 (outline->tags[point] & FT_Curve_Tag_On) ==
2058 (outline->tags[point-1] & FT_Curve_Tag_On));
2059 /* At the end of a contour Windows adds the start point,
2060 but only for Beziers and we've already done that.
2061 */
2062 if (point <= outline->contours[contour] &&
2063 outline->tags[point] & FT_Curve_Tag_On)
2064 {
2065 /* This is the closing pt of a bezier, but we've already
2066 added it, so just inc point and carry on */
2067 point++;
2068 }
2069 if (pvBuf)
2070 {
2071 ppc->wType = type;
2072 ppc->cpfx = cpfx;
2073 }
2074 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2075 }
2076 if (pvBuf) pph->cb = needed - pph_start;
2077 }
2078 break;
2079 }
2080
2081 default:
2082 DPRINT1("Unsupported format %d\n", iFormat);
2083 return GDI_ERROR;
2084 }
2085
2086 DPRINT("ftGdiGetGlyphOutline END and needed %d\n", needed);
2087 return needed;
2088 }
2089
2090 BOOL
2091 FASTCALL
2092 TextIntGetTextExtentPoint(PDC dc,
2093 PTEXTOBJ TextObj,
2094 LPCWSTR String,
2095 int Count,
2096 int MaxExtent,
2097 LPINT Fit,
2098 LPINT Dx,
2099 LPSIZE Size)
2100 {
2101 PFONTGDI FontGDI;
2102 FT_Face face;
2103 FT_GlyphSlot glyph;
2104 FT_Glyph realglyph;
2105 INT error, n, glyph_index, i, previous;
2106 ULONGLONG TotalWidth = 0;
2107 FT_CharMap charmap, found = NULL;
2108 BOOL use_kerning;
2109 FT_Render_Mode RenderMode;
2110 BOOLEAN Render;
2111
2112 FontGDI = ObjToGDI(TextObj->Font, FONT);
2113
2114 face = FontGDI->face;
2115 if (NULL != Fit)
2116 {
2117 *Fit = 0;
2118 }
2119
2120 IntLockFreeType;
2121 if (face->charmap == NULL)
2122 {
2123 DPRINT("WARNING: No charmap selected!\n");
2124 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2125
2126 for (n = 0; n < face->num_charmaps; n++)
2127 {
2128 charmap = face->charmaps[n];
2129 DPRINT("found charmap encoding: %u\n", charmap->encoding);
2130 if (charmap->encoding != 0)
2131 {
2132 found = charmap;
2133 break;
2134 }
2135 }
2136
2137 if (! found)
2138 {
2139 DPRINT1("WARNING: Could not find desired charmap!\n");
2140 }
2141
2142 error = FT_Set_Charmap(face, found);
2143 if (error)
2144 {
2145 DPRINT1("WARNING: Could not set the charmap!\n");
2146 }
2147 }
2148
2149 Render = IntIsFontRenderingEnabled();
2150 if (Render)
2151 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
2152 else
2153 RenderMode = FT_RENDER_MODE_MONO;
2154
2155 error = FT_Set_Pixel_Sizes(face,
2156 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
2157 /* FIXME should set character height if neg */
2158 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
2159 - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
2160 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
2161 if (error)
2162 {
2163 DPRINT1("Error in setting pixel sizes: %u\n", error);
2164 }
2165
2166 use_kerning = FT_HAS_KERNING(face);
2167 previous = 0;
2168
2169 for (i = 0; i < Count; i++)
2170 {
2171 glyph_index = FT_Get_Char_Index(face, *String);
2172 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
2173 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
2174 {
2175 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2176 if (error)
2177 {
2178 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
2179 break;
2180 }
2181
2182 glyph = face->glyph;
2183 realglyph = ftGdiGlyphCacheSet(face, glyph_index,
2184 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
2185 if (!realglyph)
2186 {
2187 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
2188 break;
2189 }
2190 }
2191
2192 /* retrieve kerning distance */
2193 if (use_kerning && previous && glyph_index)
2194 {
2195 FT_Vector delta;
2196 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
2197 TotalWidth += delta.x;
2198 }
2199
2200 TotalWidth += realglyph->advance.x >> 10;
2201
2202 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
2203 {
2204 *Fit = i + 1;
2205 }
2206 if (NULL != Dx)
2207 {
2208 Dx[i] = (TotalWidth + 32) >> 6;
2209 }
2210
2211 previous = glyph_index;
2212 String++;
2213 }
2214 IntUnLockFreeType;
2215
2216 Size->cx = (TotalWidth + 32) >> 6;
2217 Size->cy = (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight);
2218 Size->cy = EngMulDiv(Size->cy, IntGdiGetDeviceCaps(dc, LOGPIXELSY), 72);
2219
2220 return TRUE;
2221 }
2222
2223
2224 INT
2225 FASTCALL
2226 ftGdiGetTextCharsetInfo(
2227 PDC Dc,
2228 LPFONTSIGNATURE lpSig,
2229 DWORD dwFlags)
2230 {
2231 PDC_ATTR Dc_Attr;
2232 UINT Ret = DEFAULT_CHARSET, i;
2233 HFONT hFont;
2234 PTEXTOBJ TextObj;
2235 PFONTGDI FontGdi;
2236 FONTSIGNATURE fs;
2237 TT_OS2 *pOS2;
2238 FT_Face Face;
2239 CHARSETINFO csi;
2240 DWORD cp, fs0;
2241 USHORT usACP, usOEM;
2242
2243 Dc_Attr = Dc->pDc_Attr;
2244 if (!Dc_Attr) Dc_Attr = &Dc->Dc_Attr;
2245 hFont = Dc_Attr->hlfntNew;
2246 TextObj = RealizeFontInit(hFont);
2247
2248 if (!TextObj)
2249 {
2250 SetLastWin32Error(ERROR_INVALID_HANDLE);
2251 return Ret;
2252 }
2253 FontGdi = ObjToGDI(TextObj->Font, FONT);
2254 Face = FontGdi->face;
2255 TEXTOBJ_UnlockText(TextObj);
2256
2257 IntLockFreeType;
2258 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2259 IntUnLockFreeType;
2260 memset(&fs, 0, sizeof(FONTSIGNATURE));
2261 if (NULL != pOS2)
2262 {
2263 fs.fsCsb[0] = pOS2->ulCodePageRange1;
2264 fs.fsCsb[1] = pOS2->ulCodePageRange2;
2265 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
2266 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
2267 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
2268 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
2269 if (pOS2->version == 0)
2270 {
2271 FT_UInt dummy;
2272
2273 if (FT_Get_First_Char( Face, &dummy ) < 0x100)
2274 fs.fsCsb[0] |= FS_LATIN1;
2275 else
2276 fs.fsCsb[0] |= FS_SYMBOL;
2277 }
2278 }
2279 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
2280 if (fs.fsCsb[0] == 0)
2281 { /* let's see if we can find any interesting cmaps */
2282 for (i = 0; i < Face->num_charmaps; i++)
2283 {
2284 switch (Face->charmaps[i]->encoding)
2285 {
2286 case FT_ENCODING_UNICODE:
2287 case FT_ENCODING_APPLE_ROMAN:
2288 fs.fsCsb[0] |= FS_LATIN1;
2289 break;
2290 case FT_ENCODING_MS_SYMBOL:
2291 fs.fsCsb[0] |= FS_SYMBOL;
2292 break;
2293 default:
2294 break;
2295 }
2296 }
2297 }
2298 if (lpSig)
2299 {
2300 RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
2301 }
2302
2303 RtlGetDefaultCodePage(&usACP, &usOEM);
2304 cp = usACP;
2305
2306 if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
2307 if (csi.fs.fsCsb[0] & fs.fsCsb[0])
2308 {
2309 DPRINT("Hit 1\n");
2310 Ret = csi.ciCharset;
2311 goto Exit;
2312 }
2313
2314 for (i = 0; i < MAXTCIINDEX; i++)
2315 {
2316 fs0 = 1L << i;
2317 if (fs.fsCsb[0] & fs0)
2318 {
2319 if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
2320 {
2321 //*cp = csi.ciACP;
2322 DPRINT("Hit 2\n");
2323 Ret = csi.ciCharset;
2324 goto Exit;
2325 }
2326 else
2327 DPRINT1("TCI failing on %x\n", fs0);
2328 }
2329 }
2330 Exit:
2331 DPRINT("CharSet %d CodePage %d\n",csi.ciCharset, csi.ciACP);
2332 return (MAKELONG(csi.ciACP, csi.ciCharset));
2333 }
2334
2335
2336 DWORD
2337 FASTCALL
2338 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
2339 {
2340 DWORD size = 0;
2341 DWORD num_ranges = 0;
2342 FT_Face face = Font->face;
2343
2344 if (face->charmap->encoding == FT_ENCODING_UNICODE)
2345 {
2346 FT_UInt glyph_code = 0;
2347 FT_ULong char_code, char_code_prev;
2348
2349 char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
2350
2351 DPRINT("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
2352 face->num_glyphs, glyph_code, char_code);
2353
2354 if (!glyph_code) return 0;
2355
2356 if (glyphset)
2357 {
2358 glyphset->ranges[0].wcLow = (USHORT)char_code;
2359 glyphset->ranges[0].cGlyphs = 0;
2360 glyphset->cGlyphsSupported = 0;
2361 }
2362
2363 num_ranges = 1;
2364 while (glyph_code)
2365 {
2366 if (char_code < char_code_prev)
2367 {
2368 DPRINT1("expected increasing char code from FT_Get_Next_Char\n");
2369 return 0;
2370 }
2371 if (char_code - char_code_prev > 1)
2372 {
2373 num_ranges++;
2374 if (glyphset)
2375 {
2376 glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
2377 glyphset->ranges[num_ranges - 1].cGlyphs = 1;
2378 glyphset->cGlyphsSupported++;
2379 }
2380 }
2381 else if (glyphset)
2382 {
2383 glyphset->ranges[num_ranges - 1].cGlyphs++;
2384 glyphset->cGlyphsSupported++;
2385 }
2386 char_code_prev = char_code;
2387 char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
2388 }
2389 }
2390 else
2391 DPRINT1("encoding %u not supported\n", face->charmap->encoding);
2392
2393 size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
2394 if (glyphset)
2395 {
2396 glyphset->cbThis = size;
2397 glyphset->cRanges = num_ranges;
2398 }
2399 return size;
2400 }
2401
2402
2403 BOOL
2404 FASTCALL
2405 ftGdiGetTextMetricsW(
2406 HDC hDC,
2407 PTMW_INTERNAL ptmwi)
2408 {
2409 PDC dc;
2410 PDC_ATTR Dc_Attr;
2411 PTEXTOBJ TextObj;
2412 PFONTGDI FontGDI;
2413 FT_Face Face;
2414 TT_OS2 *pOS2;
2415 TT_HoriHeader *pHori;
2416 FT_WinFNT_HeaderRec Win;
2417 ULONG Error;
2418 NTSTATUS Status = STATUS_SUCCESS;
2419
2420 if (!ptmwi)
2421 {
2422 SetLastWin32Error(STATUS_INVALID_PARAMETER);
2423 return FALSE;
2424 }
2425
2426 if (!(dc = DC_LockDc(hDC)))
2427 {
2428 SetLastWin32Error(ERROR_INVALID_HANDLE);
2429 return FALSE;
2430 }
2431 Dc_Attr = dc->pDc_Attr;
2432 if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
2433 TextObj = RealizeFontInit(Dc_Attr->hlfntNew);
2434 if (NULL != TextObj)
2435 {
2436 FontGDI = ObjToGDI(TextObj->Font, FONT);
2437
2438 Face = FontGDI->face;
2439 IntLockFreeType;
2440 Error = FT_Set_Pixel_Sizes(Face,
2441 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
2442 /* FIXME should set character height if neg */
2443 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
2444 - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
2445 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
2446 IntUnLockFreeType;
2447 if (0 != Error)
2448 {
2449 DPRINT1("Error in setting pixel sizes: %u\n", Error);
2450 Status = STATUS_UNSUCCESSFUL;
2451 }
2452 else
2453 {
2454 Status = STATUS_SUCCESS;
2455
2456 IntLockFreeType;
2457 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
2458 if (NULL == pOS2)
2459 {
2460 DPRINT1("Can't find OS/2 table - not TT font?\n");
2461 Status = STATUS_INTERNAL_ERROR;
2462 }
2463
2464 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
2465 if (NULL == pHori)
2466 {
2467 DPRINT1("Can't find HHEA table - not TT font?\n");
2468 Status = STATUS_INTERNAL_ERROR;
2469 }
2470
2471 Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
2472
2473 IntUnLockFreeType;
2474
2475 if (NT_SUCCESS(Status))
2476 {
2477 if (!(FontGDI->flRealizedType & FDM_TYPE_TEXT_METRIC))
2478 {
2479 FillTM(&FontGDI->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
2480 FontGDI->flRealizedType |= FDM_TYPE_TEXT_METRIC;
2481 }
2482
2483 RtlCopyMemory(&ptmwi->TextMetric, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
2484 /* FIXME: Fill Diff member */
2485 RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
2486 }
2487 }
2488 TEXTOBJ_UnlockText(TextObj);
2489 }
2490 else
2491 {
2492 Status = STATUS_INVALID_HANDLE;
2493 }
2494 DC_UnlockDc(dc);
2495
2496 if (!NT_SUCCESS(Status))
2497 {
2498 SetLastNtError(Status);
2499 return FALSE;
2500 }
2501 return TRUE;
2502 }
2503
2504
2505 DWORD
2506 FASTCALL
2507 ftGdiGetFontData(
2508 PFONTGDI FontGdi,
2509 DWORD Table,
2510 DWORD Offset,
2511 PVOID Buffer,
2512 DWORD Size)
2513 {
2514 DWORD Result = GDI_ERROR;
2515
2516 IntLockFreeType;
2517
2518 if (FT_IS_SFNT(FontGdi->face))
2519 {
2520 if (Table)
2521 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
2522 (Table << 8 & 0xFF0000);
2523
2524 if (!Buffer) Size = 0;
2525
2526 if (Buffer && Size)
2527 {
2528 FT_Error Error;
2529 FT_ULong Needed = 0;
2530
2531 Error = FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, NULL, &Needed);
2532
2533 if ( !Error && Needed < Size) Size = Needed;
2534 }
2535 if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
2536 Result = Size;
2537 }
2538
2539 IntUnLockFreeType;
2540
2541 return Result;
2542 }
2543
2544 static UINT FASTCALL
2545 GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
2546 {
2547 ANSI_STRING EntryFaceNameA;
2548 UNICODE_STRING EntryFaceNameW;
2549 unsigned Size;
2550 OUTLINETEXTMETRICW *Otm;
2551 LONG WeightDiff;
2552 NTSTATUS Status;
2553 UINT Score = 1;
2554
2555 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
2556 Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2557 if (NT_SUCCESS(Status))
2558 {
2559 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2560 {
2561 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2562 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2563 }
2564 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
2565 {
2566 Score += 49;
2567 }
2568 RtlFreeUnicodeString(&EntryFaceNameW);
2569 }
2570
2571 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2572 Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
2573 if (NULL == Otm)
2574 {
2575 return Score;
2576 }
2577 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2578
2579 if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
2580 (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
2581 {
2582 Score += 25;
2583 }
2584 if (LogFont->lfWeight != FW_DONTCARE)
2585 {
2586 if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
2587 {
2588 WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
2589 }
2590 else
2591 {
2592 WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
2593 }
2594 Score += (1000 - WeightDiff) / (1000 / 25);
2595 }
2596 else
2597 {
2598 Score += 25;
2599 }
2600
2601 ExFreePool(Otm);
2602
2603 return Score;
2604 }
2605
2606 static __inline VOID
2607 FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
2608 PUNICODE_STRING FaceName, PLIST_ENTRY Head)
2609 {
2610 PLIST_ENTRY Entry;
2611 PFONT_ENTRY CurrentEntry;
2612 FONTGDI *FontGDI;
2613 UINT Score;
2614
2615 Entry = Head->Flink;
2616 while (Entry != Head)
2617 {
2618 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2619
2620 FontGDI = CurrentEntry->Font;
2621 ASSERT(FontGDI);
2622
2623 Score = GetFontScore(LogFont, FaceName, FontGDI);
2624 if (*MatchScore == 0 || *MatchScore < Score)
2625 {
2626 *FontObj = GDIToObj(FontGDI, FONT);
2627 *MatchScore = Score;
2628 }
2629 Entry = Entry->Flink;
2630 }
2631 }
2632
2633 static __inline BOOLEAN
2634 SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
2635 LPCWSTR Key)
2636 {
2637 RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
2638 NTSTATUS Status;
2639 UNICODE_STRING Value;
2640
2641 RtlInitUnicodeString(&Value, NULL);
2642
2643 QueryTable[0].QueryRoutine = NULL;
2644 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
2645 RTL_QUERY_REGISTRY_REQUIRED;
2646 QueryTable[0].Name = FaceName->Buffer;
2647 QueryTable[0].EntryContext = &Value;
2648 QueryTable[0].DefaultType = REG_NONE;
2649 QueryTable[0].DefaultData = NULL;
2650 QueryTable[0].DefaultLength = 0;
2651
2652 QueryTable[1].QueryRoutine = NULL;
2653 QueryTable[1].Name = NULL;
2654
2655 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2656 Key,
2657 QueryTable,
2658 NULL,
2659 NULL);
2660 if (NT_SUCCESS(Status))
2661 {
2662 RtlFreeUnicodeString(FaceName);
2663 *FaceName = Value;
2664 }
2665
2666 return NT_SUCCESS(Status);
2667 }
2668
2669 static __inline void
2670 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
2671 {
2672 if (10 < Level) /* Enough is enough */
2673 {
2674 return;
2675 }
2676
2677 if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
2678 SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
2679 {
2680 SubstituteFontFamily(FaceName, Level + 1);
2681 }
2682 }
2683
2684 static
2685 VOID
2686 FASTCALL
2687 IntFontType(PFONTGDI Font)
2688 {
2689 PS_FontInfoRec psfInfo;
2690 FT_ULong tmp_size = 0;
2691
2692 if (FT_HAS_MULTIPLE_MASTERS(Font->face))
2693 Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
2694 if (FT_HAS_VERTICAL( Font->face ))
2695 Font->FontObj.flFontType |= FO_VERT_FACE;
2696 if (FT_IS_SCALABLE( Font->face ))
2697 Font->FontObj.flFontType |= FO_TYPE_RASTER;
2698 if (FT_IS_SFNT(Font->face))
2699 {
2700 Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
2701 if (FT_Get_Sfnt_Table(Font->face, ft_sfnt_post))
2702 Font->FontObj.flFontType |= FO_POSTSCRIPT;
2703 }
2704 if (!FT_Get_PS_Font_Info(Font->face, &psfInfo ))
2705 {
2706 Font->FontObj.flFontType |= FO_POSTSCRIPT;
2707 }
2708 /* check for the presence of the 'CFF ' table to check if the font is Type1 */
2709 if (!FT_Load_Sfnt_Table(Font->face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
2710 {
2711 Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
2712 }
2713 }
2714
2715 NTSTATUS
2716 FASTCALL
2717 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
2718 {
2719 NTSTATUS Status = STATUS_SUCCESS;
2720 PTEXTOBJ TextObj;
2721 UNICODE_STRING FaceName;
2722 PW32PROCESS Win32Process;
2723 UINT MatchScore;
2724
2725 if (!pTextObj)
2726 {
2727 TextObj = TEXTOBJ_LockText(FontHandle);
2728 if (NULL == TextObj)
2729 {
2730 return STATUS_INVALID_HANDLE;
2731 }
2732
2733 if (TextObj->fl & TEXTOBJECT_INIT)
2734 {
2735 TEXTOBJ_UnlockText(TextObj);
2736 return STATUS_SUCCESS;
2737 }
2738 }
2739 else
2740 TextObj = pTextObj;
2741
2742 if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName))
2743 {
2744 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
2745 return STATUS_NO_MEMORY;
2746 }
2747 SubstituteFontFamily(&FaceName, 0);
2748 MatchScore = 0;
2749 TextObj->Font = NULL;
2750
2751 /* First search private fonts */
2752 Win32Process = PsGetCurrentProcessWin32Process();
2753 IntLockProcessPrivateFonts(Win32Process);
2754 FindBestFontFromList(&TextObj->Font, &MatchScore,
2755 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
2756 &Win32Process->PrivateFontListHead);
2757 IntUnLockProcessPrivateFonts(Win32Process);
2758
2759 /* Search system fonts */
2760 IntLockGlobalFonts;
2761 FindBestFontFromList(&TextObj->Font, &MatchScore,
2762 &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
2763 &FontListHead);
2764 IntUnLockGlobalFonts;
2765 if (NULL == TextObj->Font)
2766 {
2767 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
2768 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName);
2769 Status = STATUS_NOT_FOUND;
2770 }
2771 else
2772 {
2773 PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
2774 // Need hdev, when freetype is loaded need to create DEVOBJ for
2775 // Consumer and Producer.
2776 TextObj->Font->iUniq = 1; // Now it can be cached.
2777 IntFontType(FontGdi);
2778 FontGdi->flType = TextObj->Font->flFontType;
2779 FontGdi->flRealizedType = 0;
2780 FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0;
2781 FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0;
2782 TextObj->fl |= TEXTOBJECT_INIT;
2783 Status = STATUS_SUCCESS;
2784 }
2785
2786 RtlFreeUnicodeString(&FaceName);
2787 if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
2788
2789 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
2790
2791 return Status;
2792 }
2793
2794
2795 static
2796 BOOL
2797 FASTCALL
2798 IntGetFullFileName(
2799 POBJECT_NAME_INFORMATION NameInfo,
2800 ULONG Size,
2801 PUNICODE_STRING FileName)
2802 {
2803 NTSTATUS Status;
2804 OBJECT_ATTRIBUTES ObjectAttributes;
2805 HANDLE hFile;
2806 IO_STATUS_BLOCK IoStatusBlock;
2807 ULONG Desired;
2808
2809 InitializeObjectAttributes(&ObjectAttributes,
2810 FileName,
2811 OBJ_CASE_INSENSITIVE,
2812 NULL,
2813 NULL);
2814
2815 Status = ZwOpenFile(
2816 &hFile,
2817 0, //FILE_READ_ATTRIBUTES,
2818 &ObjectAttributes,
2819 &IoStatusBlock,
2820 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2821 0);
2822
2823 if (!NT_SUCCESS(Status))
2824 {
2825 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
2826 return FALSE;
2827 }
2828
2829 Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
2830 ZwClose(hFile);
2831 if (!NT_SUCCESS(Status))
2832 {
2833 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
2834 return FALSE;
2835 }
2836
2837 return TRUE;
2838 }
2839
2840 BOOL
2841 FASTCALL
2842 IntGdiGetFontResourceInfo(
2843 PUNICODE_STRING FileName,
2844 PVOID pBuffer,
2845 DWORD *pdwBytes,
2846 DWORD dwType)
2847 {
2848 UNICODE_STRING EntryFileName;
2849 POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
2850 PLIST_ENTRY ListEntry;
2851 PFONT_ENTRY FontEntry;
2852 FONTFAMILYINFO Info;
2853 ULONG Size;
2854 BOOL bFound = FALSE;
2855
2856 /* Create buffer for full path name */
2857 Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
2858 NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
2859 if (!NameInfo1)
2860 {
2861 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2862 return FALSE;
2863 }
2864
2865 /* Get the full path name */
2866 if (!IntGetFullFileName(NameInfo1, Size, FileName))
2867 {
2868 ExFreePool(NameInfo1);
2869 return FALSE;
2870 }
2871
2872 /* Create a buffer for the entries' names */
2873 NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
2874 if (!NameInfo2)
2875 {
2876 ExFreePool(NameInfo1);
2877 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2878 return FALSE;
2879 }
2880
2881 /* Try to find the pathname in the global font list */
2882 IntLockGlobalFonts;
2883 for (ListEntry = FontListHead.Flink;
2884 ListEntry != &FontListHead;
2885 ListEntry = ListEntry->Flink)
2886 {
2887 FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
2888 if (FontEntry->Font->Filename != NULL)
2889 {
2890 RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
2891 if (IntGetFullFileName(NameInfo2, Size, &EntryFileName))
2892 {
2893 if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
2894 {
2895 /* found */
2896 FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font);
2897 bFound = TRUE;
2898 break;
2899 }
2900 }
2901 }
2902 }
2903 IntUnLockGlobalFonts;
2904
2905 /* Free the buffers */
2906 ExFreePool(NameInfo1);
2907 ExFreePool(NameInfo2);
2908
2909 if (!bFound && dwType != 5)
2910 {
2911 /* Font could not be found in system table
2912 dwType == 5 will still handle this */
2913 return FALSE;
2914 }
2915
2916 switch (dwType)
2917 {
2918 case 0: /* FIXME: returns 1 or 2, don't know what this is atm */
2919 *(DWORD*)pBuffer = 1;
2920 *pdwBytes = sizeof(DWORD);
2921 break;
2922
2923 case 1: /* Copy the full font name */
2924 Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1;
2925 Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR);
2926 RtlCopyMemory(pBuffer, Info.EnumLogFontEx.elfFullName, Size);
2927 // FIXME: Do we have to zeroterminate?
2928 *pdwBytes = Size;
2929 break;
2930
2931 case 2: /* Copy a LOGFONTW structure */
2932 Info.EnumLogFontEx.elfLogFont.lfWidth = 0;
2933 RtlCopyMemory(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
2934 *pdwBytes = sizeof(LOGFONTW);
2935 break;
2936
2937 case 3: /* FIXME: What exactly is copied here? */
2938 *(DWORD*)pBuffer = 1;
2939 *pdwBytes = sizeof(DWORD*);
2940 break;
2941
2942 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
2943 *(BOOL*)pBuffer = !bFound;
2944 *pdwBytes = sizeof(BOOL);
2945 break;
2946
2947 default:
2948 return FALSE;
2949 }
2950
2951 return TRUE;
2952 }
2953
2954
2955 BOOL
2956 FASTCALL
2957 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
2958 {
2959 if (FT_HAS_FIXED_SIZES(Font->face))
2960 Info->iTechnology = RI_TECH_BITMAP;
2961 else
2962 {
2963 if (FT_IS_SCALABLE(Font->face))
2964 Info->iTechnology = RI_TECH_SCALABLE;
2965 else
2966 Info->iTechnology = RI_TECH_FIXED;
2967 }
2968 Info->iUniq = Font->FontObj.iUniq;
2969 Info->dwUnknown = -1;
2970 return TRUE;
2971 }
2972
2973
2974 DWORD
2975 FASTCALL
2976 ftGdiGetKerningPairs( PFONTGDI Font,
2977 DWORD cPairs,
2978 LPKERNINGPAIR pKerningPair)
2979 {
2980 DWORD Count = 0;
2981 INT i = 0;
2982 FT_Face face = Font->face;
2983
2984 if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
2985 {
2986 FT_UInt previous_index = 0, glyph_index = 0;
2987 FT_ULong char_code, char_previous;
2988 FT_Vector delta;
2989
2990 char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
2991
2992 IntLockFreeType;
2993
2994 while (glyph_index)
2995 {
2996 if (previous_index && glyph_index)
2997 {
2998 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
2999
3000 if (pKerningPair && cPairs)
3001 {
3002 pKerningPair[i].wFirst = char_previous;
3003 pKerningPair[i].wSecond = char_code;
3004 pKerningPair[i].iKernAmount = delta.x;
3005 i++;
3006 if (i == cPairs) break;
3007 }
3008 Count++;
3009 }
3010 previous_index = glyph_index;
3011 char_previous = char_code;
3012 char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
3013 }
3014 IntUnLockFreeType;
3015 }
3016 return Count;
3017 }
3018
3019
3020 //////////////////
3021 //
3022 // Functions needing sorting.
3023 //
3024 ///////////////
3025 int APIENTRY
3026 NtGdiGetFontFamilyInfo(HDC Dc,
3027 LPLOGFONTW UnsafeLogFont,
3028 PFONTFAMILYINFO UnsafeInfo,
3029 DWORD Size)
3030 {
3031 NTSTATUS Status;
3032 LOGFONTW LogFont;
3033 PFONTFAMILYINFO Info;
3034 DWORD Count;
3035 PW32PROCESS Win32Process;
3036
3037 /* Make a safe copy */
3038 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
3039 if (! NT_SUCCESS(Status))
3040 {
3041 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3042 return -1;
3043 }
3044
3045 /* Allocate space for a safe copy */
3046 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), TAG_GDITEXT);
3047 if (NULL == Info)
3048 {
3049 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3050 return -1;
3051 }
3052
3053 /* Enumerate font families in the global list */
3054 IntLockGlobalFonts;
3055 Count = 0;
3056 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
3057 {
3058 IntUnLockGlobalFonts;
3059 ExFreePool(Info);
3060 return -1;
3061 }
3062 IntUnLockGlobalFonts;
3063
3064 /* Enumerate font families in the process local list */
3065 Win32Process = PsGetCurrentProcessWin32Process();
3066 IntLockProcessPrivateFonts(Win32Process);
3067 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
3068 &Win32Process->PrivateFontListHead))
3069 {
3070 IntUnLockProcessPrivateFonts(Win32Process);
3071 ExFreePool(Info);
3072 return -1;
3073 }
3074 IntUnLockProcessPrivateFonts(Win32Process);
3075
3076 /* Enumerate font families in the registry */
3077 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
3078 {
3079 ExFreePool(Info);
3080 return -1;
3081 }
3082
3083 /* Return data to caller */
3084 if (0 != Count)
3085 {
3086 Status = MmCopyToCaller(UnsafeInfo, Info,
3087 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
3088 if (! NT_SUCCESS(Status))
3089 {
3090 ExFreePool(Info);
3091 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3092 return -1;
3093 }
3094 }
3095
3096 ExFreePool(Info);
3097
3098 return Count;
3099 }
3100
3101 BOOL
3102 APIENTRY
3103 GreExtTextOutW(
3104 IN HDC hDC,
3105 IN INT XStart,
3106 IN INT YStart,
3107 IN UINT fuOptions,
3108 IN OPTIONAL LPRECT lprc,
3109 IN LPWSTR String,
3110 IN INT Count,
3111 IN OPTIONAL LPINT Dx,
3112 IN DWORD dwCodePage)
3113 {
3114 /*
3115 * FIXME:
3116 * Call EngTextOut, which does the real work (calling DrvTextOut where
3117 * appropriate)
3118 */
3119
3120 DC *dc;
3121 PDC_ATTR Dc_Attr;
3122 SURFOBJ *SurfObj;
3123 SURFACE *psurf = NULL;
3124 int error, glyph_index, n, i;
3125 FT_Face face;
3126 FT_GlyphSlot glyph;
3127 FT_Glyph realglyph;
3128 FT_BitmapGlyph realglyph2;
3129 LONGLONG TextLeft, RealXStart;
3130 ULONG TextTop, previous, BackgroundLeft;
3131 FT_Bool use_kerning;
3132 RECTL DestRect, MaskRect;
3133 POINTL SourcePoint, BrushOrigin;
3134 HBRUSH hBrushFg = NULL;
3135 PGDIBRUSHOBJ BrushFg = NULL;
3136 GDIBRUSHINST BrushFgInst;
3137 HBRUSH hBrushBg = NULL;
3138 PGDIBRUSHOBJ BrushBg = NULL;
3139 GDIBRUSHINST BrushBgInst;
3140 HBITMAP HSourceGlyph;
3141 SURFOBJ *SourceGlyphSurf;
3142 SIZEL bitSize;
3143 FT_CharMap found = 0, charmap;
3144 INT yoff;
3145 FONTOBJ *FontObj;
3146 PFONTGDI FontGDI;
3147 PTEXTOBJ TextObj = NULL;
3148 PPALGDI PalDestGDI;
3149 XLATEOBJ *XlateObj=NULL, *XlateObj2=NULL;
3150 ULONG Mode;
3151 FT_Render_Mode RenderMode;
3152 BOOLEAN Render;
3153 POINT Start;
3154 BOOL DoBreak = FALSE;
3155 HPALETTE hDestPalette;
3156 USHORT DxShift;
3157
3158 // TODO: Write test-cases to exactly match real Windows in different
3159 // bad parameters (e.g. does Windows check the DC or the RECT first?).
3160 dc = DC_LockDc(hDC);
3161 if (!dc)
3162 {
3163 SetLastWin32Error(ERROR_INVALID_HANDLE);
3164 return FALSE;
3165 }
3166 if (dc->DC_Type == DC_TYPE_INFO)
3167 {
3168 DC_UnlockDc(dc);
3169 /* Yes, Windows really returns TRUE in this case */
3170 return TRUE;
3171 }
3172
3173 Dc_Attr = dc->pDc_Attr;
3174 if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
3175
3176 /* Check if String is valid */
3177 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
3178 {
3179 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3180 goto fail;
3181 }
3182
3183 DxShift = fuOptions & ETO_PDY ? 1 : 0;
3184
3185 if (PATH_IsPathOpen(dc->DcLevel))
3186 {
3187 if (!PATH_ExtTextOut( dc,
3188 XStart,
3189 YStart,
3190 fuOptions,
3191 (const RECT *)lprc,
3192 String,
3193 Count,
3194 (const INT *)Dx)) goto fail;
3195 goto good;
3196 }
3197
3198 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
3199 {
3200 IntLPtoDP(dc, (POINT *)lprc, 2);
3201 }
3202
3203 psurf = SURFACE_LockSurface(dc->w.hBitmap);
3204 if (!psurf)
3205 {
3206 goto fail;
3207 }
3208 SurfObj = &psurf->SurfObj;
3209 ASSERT(SurfObj);
3210
3211 Start.x = XStart;
3212 Start.y = YStart;
3213 IntLPtoDP(dc, &Start, 1);
3214
3215 RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;
3216 YStart = Start.y + dc->ptlDCOrig.y;
3217
3218 /* Create the brushes */
3219 hDestPalette = psurf->hDIBPalette;
3220 if (!hDestPalette) hDestPalette = pPrimarySurface->DevInfo.hpalDefault;
3221 PalDestGDI = PALETTE_LockPalette(hDestPalette);
3222 if ( !PalDestGDI )
3223 Mode = PAL_RGB;
3224 else
3225 {
3226 Mode = PalDestGDI->Mode;
3227 PALETTE_UnlockPalette(PalDestGDI);
3228 }
3229 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, hDestPalette, NULL);
3230 if ( !XlateObj )
3231 {
3232 goto fail;
3233 }
3234 hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, Dc_Attr->crForegroundClr), 0);
3235 if ( !hBrushFg )
3236 {
3237 goto fail;
3238 }
3239 BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
3240 if ( !BrushFg )
3241 {
3242 goto fail;
3243 }
3244 IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);
3245 if ((fuOptions & ETO_OPAQUE) || Dc_Attr->jBkMode == OPAQUE)
3246 {
3247 hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, Dc_Attr->crBackgroundClr), 0);
3248 if ( !hBrushBg )
3249 {
3250 goto fail;
3251 }
3252 BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
3253 if ( !BrushBg )
3254 {
3255 goto fail;
3256 }
3257 IntGdiInitBrushInstance(&BrushBgInst, BrushBg, NULL);
3258 }
3259 XlateObj2 = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, Mode, NULL, hDestPalette);
3260 if ( !XlateObj2 )
3261 {
3262 goto fail;
3263 }
3264
3265 SourcePoint.x = 0;
3266 SourcePoint.y = 0;
3267 MaskRect.left = 0;
3268 MaskRect.top = 0;
3269 BrushOrigin.x = 0;
3270 BrushOrigin.y = 0;
3271
3272 if ((fuOptions & ETO_OPAQUE) && lprc)
3273 {
3274 DestRect.left = lprc->left + dc->ptlDCOrig.x;
3275 DestRect.top = lprc->top + dc->ptlDCOrig.y;
3276 DestRect.right = lprc->right + dc->ptlDCOrig.x;
3277 DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
3278 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
3279 IntEngBitBlt(
3280 &psurf->SurfObj,
3281 NULL,
3282 NULL,
3283 dc->CombinedClip,
3284 NULL,
3285 &DestRect,
3286 &SourcePoint,
3287 &SourcePoint,
3288 &BrushBgInst.BrushObject,
3289 &BrushOrigin,
3290 ROP3_TO_ROP4(PATCOPY));
3291 fuOptions &= ~ETO_OPAQUE;
3292 }
3293 else
3294 {
3295 if (Dc_Attr->jBkMode == OPAQUE)
3296 {
3297 fuOptions |= ETO_OPAQUE;
3298 }
3299 }
3300
3301 TextObj = RealizeFontInit(Dc_Attr->hlfntNew);
3302 if (TextObj == NULL)
3303 {
3304 goto fail;
3305 }
3306
3307 FontObj = TextObj->Font;
3308 ASSERT(FontObj);
3309 FontGDI = ObjToGDI(FontObj, FONT);
3310 ASSERT(FontGDI);
3311
3312 IntLockFreeType;
3313 face = FontGDI->face;
3314 if (face->charmap == NULL)
3315 {
3316 DPRINT("WARNING: No charmap selected!\n");
3317 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3318
3319 for (n = 0; n < face->num_charmaps; n++)
3320 {
3321 charmap = face->charmaps[n];
3322 DPRINT("found charmap encoding: %u\n", charmap->encoding);
3323 if (charmap->encoding != 0)
3324 {
3325 found = charmap;
3326 break;
3327 }
3328 }
3329 if (!found)
3330 {
3331 DPRINT1("WARNING: Could not find desired charmap!\n");
3332 }
3333 error = FT_Set_Charmap(face, found);
3334 if (error)
3335 {
3336 DPRINT1("WARNING: Could not set the charmap!\n");
3337 }
3338 }
3339
3340 Render = IntIsFontRenderingEnabled();
3341 if (Render)
3342 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
3343 else
3344 RenderMode = FT_RENDER_MODE_MONO;
3345
3346 error = FT_Set_Pixel_Sizes(
3347 face,
3348 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
3349 /* FIXME should set character height if neg */
3350 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
3351 - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
3352 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
3353 if (error)
3354 {
3355 DPRINT1("Error in setting pixel sizes: %u\n", error);
3356 IntUnLockFreeType;
3357 goto fail;
3358 }
3359
3360 /*
3361 * Process the vertical alignment and determine the yoff.
3362 */
3363
3364 if (Dc_Attr->lTextAlign & TA_BASELINE)
3365 yoff = 0;
3366 else if (Dc_Attr->lTextAlign & TA_BOTTOM)
3367 yoff = -face->size->metrics.descender >> 6;
3368 else /* TA_TOP */
3369 yoff = face->size->metrics.ascender >> 6;
3370
3371 use_kerning = FT_HAS_KERNING(face);
3372 previous = 0;
3373
3374 /*
3375 * Process the horizontal alignment and modify XStart accordingly.
3376 */
3377
3378 if (Dc_Attr->lTextAlign & (TA_RIGHT | TA_CENTER))
3379 {
3380 ULONGLONG TextWidth = 0;
3381 LPCWSTR TempText = String;
3382 int Start;
3383
3384 /*
3385 * Calculate width of the text.
3386 */
3387
3388 if (NULL != Dx)
3389 {
3390 Start = Count < 2 ? 0 : Count - 2;
3391 TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
3392 }
3393 else
3394 {
3395 Start = 0;
3396 }
3397 TempText = String + Start;
3398
3399 for (i = Start; i < Count; i++)
3400 {
3401 if (fuOptions & ETO_GLYPH_INDEX)
3402 glyph_index = *TempText;
3403 else
3404 glyph_index = FT_Get_Char_Index(face, *TempText);
3405
3406 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3407 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
3408 {
3409 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3410 if (error)
3411 {
3412 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3413 }
3414
3415 glyph = face->glyph;
3416 realglyph = ftGdiGlyphCacheSet(face, glyph_index,
3417 TextObj->logfont.elfEnumLogfontEx.elfLogFont.