f5b660d85af01f18eb71886e36540c4f4abfada5
[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 /* FIXME : This is ugly, but this function must be rewritten anyway */
3191 DC_vPrepareDCsForBlit(dc, dc->rosdc.CombinedClip->rclBounds, NULL, DestRect);
3192
3193 pdcattr = dc->pdcattr;
3194
3195 if (pdcattr->ulDirty_ & DIRTY_TEXT)
3196 DC_vUpdateTextBrush(dc);
3197
3198 if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE)
3199 {
3200 if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
3201 DC_vUpdateBackgroundBrush(dc);
3202 }
3203
3204 /* Check if String is valid */
3205 if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
3206 {
3207 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3208 goto fail;
3209 }
3210
3211 DxShift = fuOptions & ETO_PDY ? 1 : 0;
3212
3213 if (PATH_IsPathOpen(dc->dclevel))
3214 {
3215 if (!PATH_ExtTextOut( dc,
3216 XStart,
3217 YStart,
3218 fuOptions,
3219 (const RECTL *)lprc,
3220 String,
3221 Count,
3222 (const INT *)Dx)) goto fail;
3223 goto good;
3224 }
3225
3226 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
3227 {
3228 IntLPtoDP(dc, (POINT *)lprc, 2);
3229 }
3230
3231 psurf = dc->dclevel.pSurface;
3232 if (!psurf)
3233 {
3234 goto fail;
3235 }
3236 SurfObj = &psurf->SurfObj;
3237
3238 Start.x = XStart;
3239 Start.y = YStart;
3240 IntLPtoDP(dc, &Start, 1);
3241
3242 RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;
3243 YStart = Start.y + dc->ptlDCOrig.y;
3244
3245 SourcePoint.x = 0;
3246 SourcePoint.y = 0;
3247 MaskRect.left = 0;
3248 MaskRect.top = 0;
3249 BrushOrigin.x = 0;
3250 BrushOrigin.y = 0;
3251
3252 if ((fuOptions & ETO_OPAQUE) && lprc)
3253 {
3254 DestRect.left = lprc->left;
3255 DestRect.top = lprc->top;
3256 DestRect.right = lprc->right;
3257 DestRect.bottom = lprc->bottom;
3258
3259 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
3260
3261 DestRect.left += dc->ptlDCOrig.x;
3262 DestRect.top += dc->ptlDCOrig.y;
3263 DestRect.right += dc->ptlDCOrig.x;
3264 DestRect.bottom += dc->ptlDCOrig.y;
3265
3266 IntEngBitBlt(
3267 &psurf->SurfObj,
3268 NULL,
3269 NULL,
3270 dc->rosdc.CombinedClip,
3271 NULL,
3272 &DestRect,
3273 &SourcePoint,
3274 &SourcePoint,
3275 &dc->eboBackground.BrushObject,
3276 &BrushOrigin,
3277 ROP3_TO_ROP4(PATCOPY));
3278 fuOptions &= ~ETO_OPAQUE;
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
3458 for (i = 0; i < Count; i++)
3459 {
3460 if (fuOptions & ETO_GLYPH_INDEX)
3461 glyph_index = *String;
3462 else
3463 glyph_index = FT_Get_Char_Index(face, *String);
3464
3465 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3466 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
3467 {
3468 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3469 if (error)
3470 {
3471 DPRINT1("Failed to load and render glyph! [index: %u]\n", glyph_index);
3472 IntUnLockFreeType;
3473 goto fail2;
3474 }
3475 glyph = face->glyph;
3476 realglyph = ftGdiGlyphCacheSet(face,
3477 glyph_index,
3478 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3479 glyph,
3480 RenderMode);
3481 if (!realglyph)
3482 {
3483 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
3484 IntUnLockFreeType;
3485 goto fail2;
3486 }
3487 }
3488
3489 /* retrieve kerning distance and move pen position */
3490 if (use_kerning && previous && glyph_index && NULL == Dx)
3491 {
3492 FT_Vector delta;
3493 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3494 TextLeft += delta.x;
3495 }
3496 DPRINT("TextLeft: %d\n", TextLeft);
3497 DPRINT("TextTop: %d\n", TextTop);
3498 DPRINT("Advance: %d\n", realglyph->root.advance.x);
3499
3500 if (fuOptions & ETO_OPAQUE)
3501 {
3502 DestRect.left = BackgroundLeft;
3503 DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
3504 DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6);
3505 DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6);
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 BackgroundLeft = DestRect.right;
3519 }
3520
3521 DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
3522 DestRect.right = DestRect.left + realglyph->bitmap.width;
3523 DestRect.top = TextTop + yoff - realglyph->top;
3524 DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
3525
3526 bitSize.cx = realglyph->bitmap.width;
3527 bitSize.cy = realglyph->bitmap.rows;
3528 MaskRect.right = realglyph->bitmap.width;
3529 MaskRect.bottom = realglyph->bitmap.rows;
3530
3531 /*
3532 * We should create the bitmap out of the loop at the biggest possible
3533 * glyph size. Then use memset with 0 to clear it and sourcerect to
3534 * limit the work of the transbitblt.
3535 */
3536
3537 HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
3538 BMF_8BPP, BMF_TOPDOWN,
3539 realglyph->bitmap.buffer);
3540 if ( !HSourceGlyph )
3541 {
3542 DPRINT1("WARNING: EngLockSurface() failed!\n");
3543 // FT_Done_Glyph(realglyph);
3544 IntUnLockFreeType;
3545 goto fail2;
3546 }
3547 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
3548 if ( !SourceGlyphSurf )
3549 {
3550 EngDeleteSurface((HSURF)HSourceGlyph);
3551 DPRINT1("WARNING: EngLockSurface() failed!\n");
3552 IntUnLockFreeType;
3553 goto fail2;
3554 }
3555
3556 /*
3557 * Use the font data as a mask to paint onto the DCs surface using a
3558 * brush.
3559 */
3560
3561 if (lprc &&
3562 (fuOptions & ETO_CLIPPED) &&
3563 DestRect.right >= lprc->right + dc->ptlDCOrig.x)
3564 {
3565 // We do the check '>=' instead of '>' to possibly save an iteration
3566 // through this loop, since it's breaking after the drawing is done,
3567 // and x is always incremented.
3568 DestRect.right = lprc->right + dc->ptlDCOrig.x;
3569 DoBreak = TRUE;
3570 }
3571
3572 IntEngMaskBlt(
3573 SurfObj,
3574 SourceGlyphSurf,
3575 dc->rosdc.CombinedClip,
3576 &exloRGB2Dst.xlo,
3577 &exloDst2RGB.xlo,
3578 &DestRect,
3579 (PPOINTL)&MaskRect,
3580 &dc->eboText.BrushObject,
3581 &BrushOrigin);
3582
3583 EngUnlockSurface(SourceGlyphSurf);
3584 EngDeleteSurface((HSURF)HSourceGlyph);
3585
3586 if (DoBreak)
3587 {
3588 break;
3589 }
3590
3591 if (NULL == Dx)
3592 {
3593 TextLeft += realglyph->root.advance.x >> 10;
3594 DPRINT("new TextLeft: %d\n", TextLeft);
3595 }
3596 else
3597 {
3598 TextLeft += Dx[i<<DxShift] << 6;
3599 DPRINT("new TextLeft2: %d\n", TextLeft);
3600 }
3601
3602 if (DxShift)
3603 {
3604 TextTop -= Dx[2 * i + 1] << 6;
3605 }
3606
3607 previous = glyph_index;
3608
3609 String++;
3610 }
3611
3612 IntUnLockFreeType;
3613
3614 EXLATEOBJ_vCleanup(&exloRGB2Dst);
3615 EXLATEOBJ_vCleanup(&exloDst2RGB);
3616 if (TextObj != NULL)
3617 TEXTOBJ_UnlockText(TextObj);
3618 good:
3619 DC_vFinishBlit(dc, NULL);
3620 DC_UnlockDc( dc );
3621
3622 return TRUE;
3623
3624 fail2:
3625 EXLATEOBJ_vCleanup(&exloRGB2Dst);
3626 EXLATEOBJ_vCleanup(&exloDst2RGB);
3627 fail:
3628 if (TextObj != NULL)
3629 TEXTOBJ_UnlockText(TextObj);
3630 DC_vFinishBlit(dc, NULL);
3631 DC_UnlockDc(dc);
3632
3633 return FALSE;
3634 }
3635
3636 #define STACK_TEXT_BUFFER_SIZE 100
3637 BOOL
3638 APIENTRY
3639 NtGdiExtTextOutW(
3640 IN HDC hDC,
3641 IN INT XStart,
3642 IN INT YStart,
3643 IN UINT fuOptions,
3644 IN OPTIONAL LPRECT UnsafeRect,
3645 IN LPWSTR UnsafeString,
3646 IN INT Count,
3647 IN OPTIONAL LPINT UnsafeDx,
3648 IN DWORD dwCodePage)
3649 {
3650 BOOL Result = FALSE;
3651 NTSTATUS Status = STATUS_SUCCESS;
3652 RECTL SafeRect;
3653 BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
3654 PVOID Buffer = LocalBuffer;
3655 LPWSTR SafeString = NULL;
3656 LPINT SafeDx = NULL;
3657 ULONG BufSize, StringSize, DxSize = 0;
3658
3659 /* Check if String is valid */
3660 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
3661 {
3662 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3663 return FALSE;
3664 }
3665
3666 if (Count > 0)
3667 {
3668 /* Calculate buffer size for string and Dx values */
3669 BufSize = StringSize = Count * sizeof(WCHAR);
3670 if (UnsafeDx)
3671 {
3672 /* If ETO_PDY is specified, we have pairs of INTs */
3673 DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
3674 BufSize += DxSize;
3675 }
3676
3677 /* Check if our local buffer is large enough */
3678 if (BufSize > STACK_TEXT_BUFFER_SIZE)
3679 {
3680 /* It's not, allocate a temp buffer */
3681 Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, TAG_GDITEXT);
3682 if (!Buffer)
3683 {
3684 return FALSE;
3685 }
3686 }
3687
3688 /* Probe and copy user mode data to the buffer */
3689 _SEH2_TRY
3690 {
3691 /* Put the Dx before the String to assure alignment of 4 */
3692 SafeString = (LPWSTR)(((ULONG_PTR)Buffer) + DxSize);
3693
3694 /* Probe and copy the string */
3695 ProbeForRead(UnsafeString, StringSize, 1);
3696 memcpy((PVOID)SafeString, UnsafeString, StringSize);
3697
3698 /* If we have Dx values... */
3699 if (UnsafeDx)
3700 {
3701 /* ... probe and copy them */
3702 SafeDx = Buffer;
3703 ProbeForRead(UnsafeDx, DxSize, 1);
3704 memcpy(SafeDx, UnsafeDx, DxSize);
3705 }
3706 }
3707 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3708 {
3709 Status = _SEH2_GetExceptionCode();
3710 }
3711 _SEH2_END
3712 if (!NT_SUCCESS(Status))
3713 {
3714 goto cleanup;
3715 }
3716 }
3717
3718 /* If we have a rect, copy it */
3719 if (UnsafeRect)
3720 {
3721 _SEH2_TRY
3722 {
3723 ProbeForRead(UnsafeRect, sizeof(RECT), 1);
3724 SafeRect = *UnsafeRect;
3725 }
3726 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3727 {
3728 Status = _SEH2_GetExceptionCode();
3729 }
3730 _SEH2_END
3731 if (!NT_SUCCESS(Status))
3732 {
3733 goto cleanup;
3734 }
3735 }
3736
3737 /* Finally call the internal routine */
3738 Result = GreExtTextOutW(hDC,
3739 XStart,
3740 YStart,
3741 fuOptions,
3742 &SafeRect,
3743 SafeString,
3744 Count,
3745 SafeDx,
3746 dwCodePage);
3747
3748 cleanup:
3749 /* If we allocated a buffer, free it */
3750 if (Buffer != LocalBuffer)
3751 {
3752 ExFreePoolWithTag(Buffer, TAG_GDITEXT);
3753 }
3754
3755 return Result;
3756 }
3757
3758
3759 /*
3760 * @implemented
3761 */
3762 BOOL
3763 APIENTRY
3764 NtGdiGetCharABCWidthsW(
3765 IN HDC hDC,
3766 IN UINT FirstChar,
3767 IN ULONG Count,
3768 IN OPTIONAL PWCHAR pwch,
3769 IN FLONG fl,
3770 OUT PVOID Buffer)
3771 {
3772 LPABC SafeBuff;
3773 LPABCFLOAT SafeBuffF = NULL;
3774 PDC dc;
3775 PDC_ATTR pdcattr;
3776 PTEXTOBJ TextObj;
3777 PFONTGDI FontGDI;
3778 FT_Face face;
3779 FT_CharMap charmap, found = NULL;
3780 UINT i, glyph_index, BufferSize;
3781 HFONT hFont = 0;
3782 NTSTATUS Status = STATUS_SUCCESS;
3783
3784 if (pwch)
3785 {
3786 _SEH2_TRY
3787 {
3788 ProbeForRead(pwch,
3789 sizeof(PWSTR),
3790 1);
3791 }
3792 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3793 {
3794 Status = _SEH2_GetExceptionCode();
3795 }
3796 _SEH2_END;
3797 }
3798 if (!NT_SUCCESS(Status))
3799 {
3800 SetLastWin32Error(Status);
3801 return FALSE;
3802 }
3803
3804 if (!Buffer)
3805 {
3806 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3807 return FALSE;
3808 }
3809
3810 BufferSize = Count * sizeof(ABC); // Same size!
3811 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
3812 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
3813 if (SafeBuff == NULL)
3814 {
3815 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3816 return FALSE;
3817 }
3818
3819 dc = DC_LockDc(hDC);
3820 if (dc == NULL)
3821 {
3822 ExFreePool(SafeBuff);
3823 SetLastWin32Error(ERROR_INVALID_HANDLE);
3824 return FALSE;
3825 }
3826 pdcattr = dc->pdcattr;
3827 hFont = pdcattr->hlfntNew;
3828 TextObj = RealizeFontInit(hFont);
3829 DC_UnlockDc(dc);
3830
3831 if (TextObj == NULL)
3832 {
3833 ExFreePool(SafeBuff);
3834 SetLastWin32Error(ERROR_INVALID_HANDLE);
3835 return FALSE;
3836 }
3837
3838 FontGDI = ObjToGDI(TextObj->Font, FONT);
3839
3840 face = FontGDI->face;
3841 if (face->charmap == NULL)
3842 {
3843 for (i = 0; i < face->num_charmaps; i++)
3844 {
3845 charmap = face->charmaps[i];
3846 if (charmap->encoding != 0)
3847 {
3848 found = charmap;
3849 break;
3850 }
3851 }
3852
3853 if (!found)
3854 {
3855 DPRINT1("WARNING: Could not find desired charmap!\n");
3856 ExFreePool(SafeBuff);
3857 SetLastWin32Error(ERROR_INVALID_HANDLE);
3858 return FALSE;
3859 }
3860
3861 IntLockFreeType;
3862 FT_Set_Charmap(face, found);
3863 IntUnLockFreeType;
3864 }
3865
3866 IntLockFreeType;
3867 FT_Set_Pixel_Sizes(face,
3868 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
3869 /* FIXME should set character height if neg */
3870 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
3871 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
3872
3873 for (i = FirstChar; i < FirstChar+Count; i++)
3874 {
3875 int adv, lsb, bbx, left, right;
3876
3877 if (pwch)
3878 {
3879 if (fl & GCABCW_INDICES)
3880 glyph_index = pwch[i - FirstChar];
3881 else
3882 glyph_index = FT_Get_Char_Index(face, pwch[i - FirstChar]);
3883 }
3884 else
3885 {
3886 if (fl & GCABCW_INDICES)
3887 glyph_index = i;
3888 else
3889 glyph_index = FT_Get_Char_Index(face, i);
3890 }
3891 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3892
3893 left = (INT)face->glyph->metrics.horiBearingX & -64;
3894 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
3895 adv = (face->glyph->advance.x + 32) >> 6;
3896
3897 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
3898 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same!*/
3899
3900 lsb = left >> 6;
3901 bbx = (right - left) >> 6;
3902 /*
3903 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
3904 */
3905 if (!fl)
3906 {
3907 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
3908 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
3909 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
3910 }
3911 else
3912 {
3913 SafeBuff[i - FirstChar].abcA = lsb;
3914 SafeBuff[i - FirstChar].abcB = bbx;
3915 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
3916 }
3917 }
3918 IntUnLockFreeType;
3919 TEXTOBJ_UnlockText(TextObj);
3920 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
3921 if (! NT_SUCCESS(Status))
3922 {
3923 SetLastNtError(Status);
3924 ExFreePool(SafeBuff);
3925 return FALSE;
3926 }
3927 ExFreePool(SafeBuff);
3928 DPRINT("NtGdiGetCharABCWidths Worked!\n");
3929 return TRUE;
3930 }
3931
3932 /*
3933 * @implemented
3934 */
3935 BOOL
3936 APIENTRY
3937 NtGdiGetCharWidthW(
3938 IN HDC hDC,
3939 IN UINT FirstChar,
3940 IN UINT Count,
3941 IN OPTIONAL PWCHAR pwc,
3942 IN FLONG fl,
3943 OUT PVOID Buffer)
3944 {
3945 NTSTATUS Status = STATUS_SUCCESS;
3946 LPINT SafeBuff;
3947 PFLOAT SafeBuffF = NULL;
3948 PDC dc;
3949 PDC_ATTR pdcattr;
3950 PTEXTOBJ TextObj;
3951 PFONTGDI FontGDI;
3952 FT_Face face;
3953 FT_CharMap charmap, found = NULL;
3954 UINT i, glyph_index, BufferSize;
3955 HFONT hFont = 0;
3956
3957 if (pwc)
3958 {
3959 _SEH2_TRY
3960 {
3961 ProbeForRead(pwc,
3962 sizeof(PWSTR),
3963 1);
3964 }
3965 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3966 {
3967 Status = _SEH2_GetExceptionCode();
3968 }
3969 _SEH2_END;
3970 }
3971 if (!NT_SUCCESS(Status))
3972 {
3973 SetLastWin32Error(Status);
3974 return FALSE;
3975 }
3976
3977 BufferSize = Count * sizeof(INT); // Same size!
3978 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
3979 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
3980 if (SafeBuff == NULL)
3981 {
3982 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3983 return FALSE;
3984 }
3985
3986 dc = DC_LockDc(hDC);
3987 if (dc == NULL)
3988 {
3989 ExFreePool(SafeBuff);
3990 SetLastWin32Error(ERROR_INVALID_HANDLE);
3991 return FALSE;
3992 }
3993 pdcattr = dc->pdcattr;
3994 hFont = pdcattr->hlfntNew;
3995 TextObj = RealizeFontInit(hFont);
3996 DC_UnlockDc(dc);
3997
3998 if (TextObj == NULL)
3999 {
4000 ExFreePool(SafeBuff);
4001 SetLastWin32Error(ERROR_INVALID_HANDLE);
4002 return FALSE;
4003 }
4004
4005 FontGDI = ObjToGDI(TextObj->Font, FONT);
4006
4007 face = FontGDI->face;
4008 if (face->charmap == NULL)
4009 {
4010 for (i = 0; i < face->num_charmaps; i++)
4011 {
4012 charmap = face->charmaps[i];
4013 if (charmap->encoding != 0)
4014 {
4015 found = charmap;
4016 break;
4017 }
4018 }
4019
4020 if (!found)
4021 {
4022 DPRINT1("WARNING: Could not find desired charmap!\n");
4023 ExFreePool(SafeBuff);
4024 SetLastWin32Error(ERROR_INVALID_HANDLE);
4025 return FALSE;
4026 }
4027
4028 IntLockFreeType;
4029 FT_Set_Charmap(face, found);
4030 IntUnLockFreeType;
4031 }
4032
4033 IntLockFreeType;
4034 FT_Set_Pixel_Sizes(face,
4035 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
4036 /* FIXME should set character height if neg */
4037 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
4038 - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
4039 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
4040
4041 for (i = FirstChar; i < FirstChar+Count; i++)
4042 {
4043 if (pwc)
4044 {
4045 if (fl & GCW_INDICES)
4046 glyph_index = pwc[i - FirstChar];
4047 else
4048 glyph_index = FT_Get_Char_Index(face, pwc[i - FirstChar]);
4049 }
4050 else
4051 {
4052 if (fl & GCW_INDICES)
4053 glyph_index = i;
4054 else
4055 glyph_index = FT_Get_Char_Index(face, i);
4056 }
4057 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
4058 if (!fl)
4059 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
4060 else
4061 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
4062 }
4063 IntUnLockFreeType;
4064 TEXTOBJ_UnlockText(TextObj);
4065 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
4066 ExFreePool(SafeBuff);
4067 return TRUE;
4068 }
4069
4070 DWORD
4071 FASTCALL
4072 GreGetGlyphIndicesW(
4073 HDC hdc,
4074 LPWSTR pwc,
4075 INT cwc,
4076 LPWORD pgi,
4077 DWORD iMode,
4078 DWORD Unknown)
4079 {
4080 PDC dc;
4081 PDC_ATTR pdcattr;
4082 PTEXTOBJ TextObj;
4083 PFONTGDI FontGDI;
4084 HFONT hFont = 0;
4085 OUTLINETEXTMETRICW *potm;
4086 INT i;
4087 FT_Face face;
4088 WCHAR DefChar = 0xffff;
4089 PWSTR Buffer = NULL;
4090 ULONG Size;
4091
4092 if ((!pwc) && (!pgi)) return cwc;
4093
4094 dc = DC_LockDc(hdc);
4095 if (!dc)
4096 {
4097 SetLastWin32Error(ERROR_INVALID_HANDLE);
4098 return GDI_ERROR;
4099 }
4100 pdcattr = dc->pdcattr;
4101 hFont = pdcattr->hlfntNew;
4102 TextObj = RealizeFontInit(hFont);
4103 DC_UnlockDc(dc);
4104 if (!TextObj)
4105 {
4106 SetLastWin32Error(ERROR_INVALID_HANDLE);
4107 return GDI_ERROR;
4108 }
4109
4110 FontGDI = ObjToGDI(TextObj->Font, FONT);
4111 TEXTOBJ_UnlockText(TextObj);
4112
4113 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), TAG_GDITEXT);
4114 if (!Buffer)
4115 {
4116 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
4117 return GDI_ERROR;
4118 }
4119
4120 if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f; /* Indicate non existence */
4121 else
4122 {
4123 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4124 potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
4125 if (!potm)
4126 {
4127 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
4128 cwc = GDI_ERROR;
4129 goto ErrorRet;
4130 }
4131 IntGetOutlineTextMetrics(FontGDI, Size, potm);
4132 DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
4133 ExFreePool(potm);
4134 }
4135
4136 IntLockFreeType;
4137 face = FontGDI->face;
4138
4139 for (i = 0; i < cwc; i++)
4140 {
4141 Buffer[i] = FT_Get_Char_Index(face, pwc[i]);
4142 if (Buffer[i] == 0)
4143 {
4144 if (DefChar == 0xffff && FT_IS_SFNT(face))
4145 {
4146 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
4147 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0);
4148 }
4149 Buffer[i] = DefChar;
4150 }
4151 }
4152
4153 IntUnLockFreeType;
4154
4155 RtlCopyMemory( pgi, Buffer, cwc*sizeof(WORD));
4156
4157 ErrorRet:
4158 if (Buffer) ExFreePoolWithTag(Buffer, TAG_GDITEXT);
4159 return cwc;
4160 }
4161
4162
4163 /*
4164 * @implemented
4165 */
4166 DWORD
4167 APIENTRY
4168 NtGdiGetGlyphIndicesW(
4169 IN HDC hdc,
4170 IN OPTIONAL LPWSTR UnSafepwc,
4171 IN INT cwc,
4172 OUT OPTIONAL LPWORD UnSafepgi,
4173 IN DWORD iMode)
4174 {
4175 PDC dc;
4176 PDC_ATTR pdcattr;
4177 PTEXTOBJ TextObj;
4178 PFONTGDI FontGDI;
4179 HFONT hFont = 0;
4180 NTSTATUS Status = STATUS_SUCCESS;
4181 OUTLINETEXTMETRICW *potm;
4182 INT i;
4183 FT_Face face;
4184 WCHAR DefChar = 0xffff;
4185 PWSTR Buffer = NULL;
4186 ULONG Size;
4187
4188 if ((!UnSafepwc) && (!UnSafepgi)) return cwc;
4189
4190 dc = DC_LockDc(hdc);
4191 if (!dc)
4192 {
4193 SetLastWin32Error(ERROR_INVALID_HANDLE);
4194 return GDI_ERROR;
4195 }
4196 pdcattr = dc->pdcattr;
4197 hFont = pdcattr->hlfntNew;
4198 TextObj = RealizeFontInit(hFont);
4199 DC_UnlockDc(dc);
4200 if (!TextObj)
4201 {
4202 SetLastWin32Error(ERROR_INVALID_HANDLE);
4203 return GDI_ERROR;
4204 }
4205
4206 FontGDI = ObjToGDI(TextObj->Font, FONT);
4207 TEXTOBJ_UnlockText(TextObj);
4208
4209 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), TAG_GDITEXT);
4210 if (!Buffer)
4211 {
4212 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
4213 return GDI_ERROR;
4214 }
4215
4216 if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f; /* Indicate non existence */
4217 else
4218 {
4219 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4220 potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
4221 if (!potm)
4222 {
4223 Status = ERROR_NOT_ENOUGH_MEMORY;
4224 goto ErrorRet;
4225 }
4226 IntGetOutlineTextMetrics(FontGDI, Size, potm);
4227 DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
4228 ExFreePool(potm);
4229 }
4230
4231 _SEH2_TRY
4232 {
4233 ProbeForRead(UnSafepwc,
4234 sizeof(PWSTR),
4235 1);
4236 }
4237 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4238 {
4239 Status = _SEH2_GetExceptionCode();
4240 }
4241 _SEH2_END;
4242
4243 if (!NT_SUCCESS(Status)) goto ErrorRet;
4244
4245 IntLockFreeType;
4246 face = FontGDI->face;
4247
4248 for (i = 0; i < cwc; i++)
4249 {
4250 Buffer[i] = FT_Get_Char_Index(face, UnSafepwc[i]);
4251 if (Buffer[i] == 0)
4252 {
4253 if (DefChar == 0xffff && FT_IS_SFNT(face))
4254 {
4255 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
4256 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0);
4257 }
4258 Buffer[i] = DefChar;
4259 }
4260 }
4261
4262 IntUnLockFreeType;
4263
4264 _SEH2_TRY
4265 {
4266 ProbeForWrite(UnSafepgi,
4267 sizeof(WORD),
4268 1);
4269 RtlCopyMemory(UnSafepgi,
4270 Buffer,
4271 cwc*sizeof(WORD));
4272 }
4273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4274 {
4275 Status = _SEH2_GetExceptionCode();
4276 }
4277 _SEH2_END;
4278
4279 ErrorRet:
4280 ExFreePoolWithTag(Buffer, TAG_GDITEXT);
4281 if (NT_SUCCESS(Status)) return cwc;
4282 SetLastWin32Error(Status);
4283 return GDI_ERROR;
4284 }
4285
4286
4287 /* EOF */