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