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