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