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