- Update Font types. Finish GetKerningPairs. Minor code cleanup.
[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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
3171 {
3172 // At least one of the two flags were specified. Copy lprc. Once.
3173 Status = MmCopyFromCaller(&SpecifiedDestRect, lprc, sizeof(RECT));
3174 if (!NT_SUCCESS(Status))
3175 {
3176 DC_UnlockDc(dc);
3177 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3178 return FALSE;
3179 }
3180 IntLPtoDP(dc, (POINT *) &SpecifiedDestRect, 2);
3181 }
3182
3183 if (NULL != UnsafeDx && Count > 0)
3184 {
3185 Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
3186 if (NULL == Dx)
3187 {
3188 goto fail;
3189 }
3190 Status = MmCopyFromCaller(Dx, UnsafeDx, Count * sizeof(INT));
3191 if (! NT_SUCCESS(Status))
3192 {
3193 goto fail;
3194 }
3195 }
3196
3197 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
3198 if ( !BitmapObj )
3199 {
3200 goto fail;
3201 }
3202 SurfObj = &BitmapObj->SurfObj;
3203 ASSERT(SurfObj);
3204
3205 Start.x = XStart; Start.y = YStart;
3206 IntLPtoDP(dc, &Start, 1);
3207
3208 RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;
3209 YStart = Start.y + dc->ptlDCOrig.y;
3210
3211 /* Create the brushes */
3212 hDestPalette = BitmapObj->hDIBPalette;
3213 if (!hDestPalette) hDestPalette = pPrimarySurface->DevInfo.hpalDefault;
3214 PalDestGDI = PALETTE_LockPalette(hDestPalette);
3215 if ( !PalDestGDI )
3216 Mode = PAL_RGB;
3217 else
3218 {
3219 Mode = PalDestGDI->Mode;
3220 PALETTE_UnlockPalette(PalDestGDI);
3221 }
3222 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, hDestPalette, NULL);
3223 if ( !XlateObj )
3224 {
3225 goto fail;
3226 }
3227 hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, Dc_Attr->crForegroundClr), 0);
3228 if ( !hBrushFg )
3229 {
3230 goto fail;
3231 }
3232 BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
3233 if ( !BrushFg )
3234 {
3235 goto fail;
3236 }
3237 IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);
3238 if ((fuOptions & ETO_OPAQUE) || Dc_Attr->jBkMode == OPAQUE)
3239 {
3240 hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, Dc_Attr->crBackgroundClr), 0);
3241 if ( !hBrushBg )
3242 {
3243 goto fail;
3244 }
3245 BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
3246 if ( !BrushBg )
3247 {
3248 goto fail;
3249 }
3250 IntGdiInitBrushInstance(&BrushBgInst, BrushBg, NULL);
3251 }
3252 XlateObj2 = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, Mode, NULL, hDestPalette);
3253 if ( !XlateObj2 )
3254 {
3255 goto fail;
3256 }
3257
3258 SourcePoint.x = 0;
3259 SourcePoint.y = 0;
3260 MaskRect.left = 0;
3261 MaskRect.top = 0;
3262 BrushOrigin.x = 0;
3263 BrushOrigin.y = 0;
3264
3265 if ((fuOptions & ETO_OPAQUE) && lprc)
3266 {
3267 DestRect.left = SpecifiedDestRect.left + dc->ptlDCOrig.x;
3268 DestRect.top = SpecifiedDestRect.top + dc->ptlDCOrig.y;
3269 DestRect.right = SpecifiedDestRect.right + dc->ptlDCOrig.x;
3270 DestRect.bottom = SpecifiedDestRect.bottom + dc->ptlDCOrig.y;
3271 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
3272 IntEngBitBlt(
3273 &BitmapObj->SurfObj,
3274 NULL,
3275 NULL,
3276 dc->CombinedClip,
3277 NULL,
3278 &DestRect,
3279 &SourcePoint,
3280 &SourcePoint,
3281 &BrushBgInst.BrushObject,
3282 &BrushOrigin,
3283 ROP3_TO_ROP4(PATCOPY));
3284 fuOptions &= ~ETO_OPAQUE;
3285 }
3286 else
3287 {
3288 if (Dc_Attr->jBkMode == OPAQUE)
3289 {
3290 fuOptions |= ETO_OPAQUE;
3291 }
3292 }
3293
3294 TextObj = RealizeFontInit(Dc_Attr->hlfntNew);
3295 if(TextObj == NULL)
3296 {
3297 goto fail;
3298 }
3299
3300 FontObj = TextObj->Font;
3301 ASSERT(FontObj);
3302 FontGDI = ObjToGDI(FontObj, FONT);
3303 ASSERT(FontGDI);
3304
3305 IntLockFreeType;
3306 face = FontGDI->face;
3307 if (face->charmap == NULL)
3308 {
3309 DPRINT("WARNING: No charmap selected!\n");
3310 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3311
3312 for (n = 0; n < face->num_charmaps; n++)
3313 {
3314 charmap = face->charmaps[n];
3315 DPRINT("found charmap encoding: %u\n", charmap->encoding);
3316 if (charmap->encoding != 0)
3317 {
3318 found = charmap;
3319 break;
3320 }
3321 }
3322 if (!found)
3323 {
3324 DPRINT1("WARNING: Could not find desired charmap!\n");
3325 }
3326 error = FT_Set_Charmap(face, found);
3327 if (error)
3328 {
3329 DPRINT1("WARNING: Could not set the charmap!\n");
3330 }
3331 }
3332
3333 Render = IntIsFontRenderingEnabled();
3334 if (Render)
3335 RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
3336 else
3337 RenderMode = FT_RENDER_MODE_MONO;
3338
3339 error = FT_Set_Pixel_Sizes(
3340 face,
3341 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
3342 /* FIXME should set character height if neg */
3343 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
3344 - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
3345 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
3346 if (error)
3347 {
3348 DPRINT1("Error in setting pixel sizes: %u\n", error);
3349 IntUnLockFreeType;
3350 goto fail;
3351 }
3352
3353 /*
3354 * Process the vertical alignment and determine the yoff.
3355 */
3356
3357 if (Dc_Attr->lTextAlign & TA_BASELINE)
3358 yoff = 0;
3359 else if (Dc_Attr->lTextAlign & TA_BOTTOM)
3360 yoff = -face->size->metrics.descender >> 6;
3361 else /* TA_TOP */
3362 yoff = face->size->metrics.ascender >> 6;
3363
3364 use_kerning = FT_HAS_KERNING(face);
3365 previous = 0;
3366
3367 /*
3368 * Process the horizontal alignment and modify XStart accordingly.
3369 */
3370
3371 if (Dc_Attr->lTextAlign & (TA_RIGHT | TA_CENTER))
3372 {
3373 ULONGLONG TextWidth = 0;
3374 LPCWSTR TempText = String;
3375 int Start;
3376
3377 /*
3378 * Calculate width of the text.
3379 */
3380
3381 if (NULL != Dx)
3382 {
3383 Start = Count < 2 ? 0 : Count - 2;
3384 TextWidth = Count < 2 ? 0 : (Dx[Count - 2] << 6);
3385 }
3386 else
3387 {
3388 Start = 0;
3389 }
3390 TempText = String + Start;
3391
3392 for (i = Start; i < Count; i++)
3393 {
3394 if (fuOptions & ETO_GLYPH_INDEX)
3395 glyph_index = *TempText;
3396 else
3397 glyph_index = FT_Get_Char_Index(face, *TempText);
3398
3399 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3400 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
3401 {
3402 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3403 if (error)
3404 {
3405 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3406 }
3407
3408 glyph = face->glyph;
3409 realglyph = ftGdiGlyphCacheSet(face, glyph_index,
3410 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
3411 if (!realglyph)
3412 {
3413 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
3414 IntUnLockFreeType;
3415 goto fail;
3416 }
3417
3418 }
3419 /* retrieve kerning distance */
3420 if (use_kerning && previous && glyph_index)
3421 {
3422 FT_Vector delta;
3423 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3424 TextWidth += delta.x;
3425 }
3426
3427 TextWidth += realglyph->advance.x >> 10;
3428
3429 previous = glyph_index;
3430 TempText++;
3431 }
3432
3433 previous = 0;
3434
3435 if (Dc_Attr->lTextAlign & TA_RIGHT)
3436 {
3437 RealXStart -= TextWidth;
3438 }
3439 else
3440 {
3441 RealXStart -= TextWidth / 2;
3442 }
3443 }
3444
3445 TextLeft = RealXStart;
3446 TextTop = YStart;
3447 BackgroundLeft = (RealXStart + 32) >> 6;
3448
3449 /*
3450 * The main rendering loop.
3451 */
3452
3453 for (i = 0; i < Count; i++)
3454 {
3455 if (fuOptions & ETO_GLYPH_INDEX)
3456 glyph_index = *String;
3457 else
3458 glyph_index = FT_Get_Char_Index(face, *String);
3459
3460 if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
3461 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
3462 {
3463 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3464 if (error)
3465 {
3466 DPRINT1("Failed to load and render glyph! [index: %u]\n", glyph_index);
3467 IntUnLockFreeType;
3468 goto fail;
3469 }
3470 glyph = face->glyph;
3471 realglyph = ftGdiGlyphCacheSet(face,
3472 glyph_index,
3473 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
3474 glyph,
3475 RenderMode);
3476 if (!realglyph)
3477 {
3478 DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
3479 IntUnLockFreeType;
3480 goto fail;
3481 }
3482 }
3483 // DbgPrint("realglyph: %x\n", realglyph);
3484 // DbgPrint("TextLeft: %d\n", TextLeft);
3485
3486 /* retrieve kerning distance and move pen position */
3487 if (use_kerning && previous && glyph_index && NULL == Dx)
3488 {
3489 FT_Vector delta;
3490 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3491 TextLeft += delta.x;
3492 }
3493 // DPRINT1("TextLeft: %d\n", TextLeft);
3494 // DPRINT1("TextTop: %d\n", TextTop);
3495
3496 if (realglyph->format == ft_glyph_format_outline)
3497 {
3498 DbgPrint("Should already be done\n");
3499 // error = FT_Render_Glyph(glyph, RenderMode);
3500 error = FT_Glyph_To_Bitmap(&realglyph, RenderMode, 0, 0);
3501 if (error)
3502 {
3503 DPRINT1("WARNING: Failed to render glyph!\n");
3504 goto fail;
3505 }
3506 }
3507 realglyph2 = (FT_BitmapGlyph)realglyph;
3508
3509 // DPRINT1("Pitch: %d\n", pitch);
3510 // DPRINT1("Advance: %d\n", realglyph->advance.x);
3511
3512 if (fuOptions & ETO_OPAQUE)
3513 {
3514 DestRect.left = BackgroundLeft;
3515 DestRect.right = (TextLeft + (realglyph->advance.x >> 10) + 32) >> 6;
3516 DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6);
3517 DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6);
3518 IntEngBitBlt(
3519 &BitmapObj->SurfObj,
3520 NULL,
3521 NULL,
3522 dc->CombinedClip,
3523 NULL,
3524 &DestRect,
3525 &SourcePoint,
3526 &SourcePoint,
3527 &BrushBgInst.BrushObject,
3528 &BrushOrigin,
3529 ROP3_TO_ROP4(PATCOPY));
3530 BackgroundLeft = DestRect.right;
3531 }
3532
3533 DestRect.left = ((TextLeft + 32) >> 6) + realglyph2->left;
3534 DestRect.right = DestRect.left + realglyph2->bitmap.width;
3535 DestRect.top = TextTop + yoff - realglyph2->top;
3536 DestRect.bottom = DestRect.top + realglyph2->bitmap.rows;
3537
3538 bitSize.cx = realglyph2->bitmap.width;
3539 bitSize.cy = realglyph2->bitmap.rows;
3540 MaskRect.right = realglyph2->bitmap.width;
3541 MaskRect.bottom = realglyph2->bitmap.rows;
3542
3543 /*
3544 * We should create the bitmap out of the loop at the biggest possible
3545 * glyph size. Then use memset with 0 to clear it and sourcerect to
3546 * limit the work of the transbitblt.
3547 *
3548 * FIXME: DIB bitmaps should have an lDelta which is a multiple of 4.
3549 * Here we pass in the pitch from the FreeType bitmap, which is not
3550 * guaranteed to be a multiple of 4. If it's not, we should expand
3551 * the FreeType bitmap to a temporary bitmap.
3552 */
3553
3554 HSourceGlyph = EngCreateBitmap(bitSize, realglyph2->bitmap.pitch,
3555 (realglyph2->bitmap.pixel_mode == ft_pixel_mode_grays) ?
3556 BMF_8BPP : BMF_1BPP, BMF_TOPDOWN,
3557 realglyph2->bitmap.buffer);
3558 if ( !HSourceGlyph )
3559 {
3560 DPRINT1("WARNING: EngLockSurface() failed!\n");
3561 // FT_Done_Glyph(realglyph);
3562 IntUnLockFreeType;
3563 goto fail;
3564 }
3565 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
3566 if ( !SourceGlyphSurf )
3567 {
3568 EngDeleteSurface((HSURF)HSourceGlyph);
3569 DPRINT1("WARNING: EngLockSurface() failed!\n");
3570 IntUnLockFreeType;
3571 goto fail;
3572 }
3573
3574 /*
3575 * Use the font data as a mask to paint onto the DCs surface using a
3576 * brush.
3577 */
3578
3579 if (lprc &&
3580 (fuOptions & ETO_CLIPPED) &&
3581 DestRect.right >= SpecifiedDestRect.right + dc->ptlDCOrig.x)
3582 {
3583 // We do the check '>=' instead of '>' to possibly save an iteration
3584 // through this loop, since it's breaking after the drawing is done,
3585 // and x is always incremented.
3586 DestRect.right = SpecifiedDestRect.right + dc->ptlDCOrig.x;
3587 DoBreak = TRUE;
3588 }
3589
3590 IntEngMaskBlt(
3591 SurfObj,
3592 SourceGlyphSurf,
3593 dc->CombinedClip,
3594 XlateObj,
3595 XlateObj2,
3596 &DestRect,
3597 &SourcePoint,
3598 (PPOINTL)&MaskRect,
3599 &BrushFgInst.BrushObject,
3600 &BrushOrigin);
3601
3602 EngUnlockSurface(SourceGlyphSurf);
3603 EngDeleteSurface((HSURF)HSourceGlyph);
3604
3605 if (DoBreak)
3606 {
3607 break;
3608 }
3609
3610 if (NULL == Dx)
3611 {
3612 TextLeft += realglyph->advance.x >> 10;
3613 // DbgPrint("new TextLeft: %d\n", TextLeft);
3614 }
3615 else
3616 {
3617 TextLeft += Dx[i] << 6;
3618 // DbgPrint("new TextLeft2: %d\n", TextLeft);
3619 }
3620 previous = glyph_index;
3621
3622 String++;
3623 }
3624
3625 IntUnLockFreeType;
3626
3627 EngDeleteXlate(XlateObj);
3628 EngDeleteXlate(XlateObj2);
3629 BITMAPOBJ_UnlockBitmap(BitmapObj);
3630 if(TextObj != NULL)
3631 TEXTOBJ_UnlockText(TextObj);
3632 if (hBrushBg != NULL)
3633 {
3634 BRUSHOBJ_UnlockBrush(BrushBg);
3635 NtGdiDeleteObject(hBrushBg);
3636 }
3637 BRUSHOBJ_UnlockBrush(BrushFg);
3638 NtGdiDeleteObject(hBrushFg);
3639 if (NULL != SafeString)
3640 {
3641 ExFreePool((void*)SafeString);
3642 }
3643 if (NULL != Dx)
3644 {
3645 ExFreePool(Dx);
3646 }
3647 DC_UnlockDc( dc );
3648
3649 return TRUE;
3650
3651 fail:
3652 if ( XlateObj2 != NULL )
3653 EngDeleteXlate(XlateObj2);
3654 if ( XlateObj != NULL )
3655 EngDeleteXlate(XlateObj);
3656 if(TextObj != NULL)
3657 TEXTOBJ_UnlockText(TextObj);
3658 if (BitmapObj != NULL)
3659 BITMAPOBJ_UnlockBitmap(BitmapObj);
3660 if (hBrushBg != NULL)
3661 {
3662 BRUSHOBJ_UnlockBrush(BrushBg);
3663 NtGdiDeleteObject(hBrushBg);
3664 }
3665 if (hBrushFg != NULL)
3666 {
3667 BRUSHOBJ_UnlockBrush(BrushFg);
3668 NtGdiDeleteObject(hBrushFg);
3669 }
3670 if (NULL != SafeString)
3671 {
3672 ExFreePool((void*)SafeString);
3673 }
3674 if (NULL != Dx)
3675 {
3676 ExFreePool(Dx);
3677 }
3678 DC_UnlockDc(dc);
3679
3680 return FALSE;
3681 }
3682
3683 /*
3684 * @implemented
3685 */
3686 BOOL
3687 STDCALL
3688 NtGdiGetCharABCWidthsW(
3689 IN HDC hDC,
3690 IN UINT FirstChar,
3691 IN ULONG Count,
3692 IN OPTIONAL PWCHAR pwch,
3693 IN FLONG fl,
3694 OUT PVOID Buffer)
3695 {
3696 LPABC SafeBuff;
3697 LPABCFLOAT SafeBuffF = NULL;
3698 PDC dc;
3699 PDC_ATTR Dc_Attr;
3700 PTEXTOBJ TextObj;
3701 PFONTGDI FontGDI;
3702 FT_Face face;
3703 FT_CharMap charmap, found = NULL;
3704 UINT i, glyph_index, BufferSize;
3705 HFONT hFont = 0;
3706 NTSTATUS Status = STATUS_SUCCESS;
3707
3708 if(pwch)
3709 {
3710 _SEH_TRY
3711 {
3712 ProbeForRead(pwch,
3713 sizeof(PWSTR),
3714 1);
3715 }
3716 _SEH_HANDLE
3717 {
3718 Status = _SEH_GetExceptionCode();
3719 }
3720 _SEH_END;
3721 }
3722 if (!NT_SUCCESS(Status))
3723 {
3724 SetLastWin32Error(Status);
3725 return FALSE;
3726 }
3727
3728 BufferSize = Count * sizeof(ABC); // Same size!
3729 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
3730 if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
3731 if (SafeBuff == NULL)
3732 {
3733 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3734 return FALSE;
3735 }
3736
3737 dc = DC_LockDc(hDC);
3738 if (dc == NULL)
3739 {
3740 ExFreePool(SafeBuff);
3741 SetLastWin32Error(ERROR_INVALID_HANDLE);
3742 return FALSE;
3743 }
3744 Dc_Attr = dc->pDc_Attr;
3745 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
3746 hFont = Dc_Attr->hlfntNew;
3747 TextObj = RealizeFontInit(hFont);
3748 DC_UnlockDc(dc);
3749
3750 if (TextObj == NULL)
3751 {
3752 ExFreePool(SafeBuff);
3753 SetLastWin32Error(ERROR_INVALID_HANDLE);
3754 return FALSE;
3755 }
3756
3757 FontGDI = ObjToGDI(TextObj->Font, FONT);
3758
3759 face = FontGDI->face;
3760 if (face->charmap == NULL)
3761 {
3762 for (i = 0; i < face->num_charmaps; i++)
3763 {
3764 charmap = face->charmaps[i];
3765 if (charmap->encoding != 0)
3766 {
3767 found = charmap;
3768 break;
3769 }
3770 }
3771
3772 if (!found)
3773 {
3774 DPRINT1("WARNING: Could not find desired charmap!\n");
3775 ExFreePool(SafeBuff);
3776 SetLastWin32Error(ERROR_INVALID_HANDLE);
3777 return FALSE;
3778 }
3779
3780 IntLockFreeType;
3781 FT_Set_Charmap(face, found);
3782 IntUnLockFreeType;
3783 }
3784
3785 IntLockFreeType;
3786 FT_Set_Pixel_Sizes(face,
3787 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
3788 /* FIXME should set character height if neg */
3789 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
3790 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
3791
3792 for (i = FirstChar; i < FirstChar+Count; i++)
3793 {
3794 int adv, lsb, bbx, left, right;
3795
3796 if (pwch)
3797 {
3798 if (fl & GCABCW_INDICES)
3799 glyph_index = pwch[i - FirstChar];
3800 else
3801 glyph_index = FT_Get_Char_Index(face, pwch[i - FirstChar]);
3802 }
3803 else
3804 {
3805 if (fl & GCABCW_INDICES)
3806 glyph_index = i;
3807 else
3808 glyph_index = FT_Get_Char_Index(face, i);
3809 }
3810 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3811
3812 left = (INT)face->glyph->metrics.horiBearingX & -64;
3813 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
3814 adv = (face->glyph->advance.x + 32) >> 6;
3815
3816 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
3817 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same!*/
3818
3819 lsb = left >> 6;
3820 bbx = (right - left) >> 6;
3821 /*
3822 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
3823 */
3824 if (!fl)
3825 {
3826 SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
3827 SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
3828 SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
3829 }
3830 else
3831 {
3832 SafeBuff[i - FirstChar].abcA = lsb;
3833 SafeBuff[i - FirstChar].abcB = bbx;
3834 SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
3835 }
3836 }
3837 IntUnLockFreeType;
3838 TEXTOBJ_UnlockText(TextObj);
3839 Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
3840 if (! NT_SUCCESS(Status))
3841 {
3842 SetLastNtError(Status);
3843 ExFreePool(SafeBuff);
3844 return FALSE;
3845 }
3846 ExFreePool(SafeBuff);
3847 DPRINT("NtGdiGetCharABCWidths Worked!\n");
3848 return TRUE;
3849 }
3850
3851 /*
3852 * @implemented
3853 */
3854 BOOL
3855 STDCALL
3856 NtGdiGetCharWidthW(
3857 IN HDC hDC,
3858 IN UINT FirstChar,
3859 IN UINT Count,
3860 IN OPTIONAL PWCHAR pwc,
3861 IN FLONG fl,
3862 OUT PVOID Buffer)
3863 {
3864 NTSTATUS Status = STATUS_SUCCESS;
3865 LPINT SafeBuff;
3866 PFLOAT SafeBuffF = NULL;
3867 PDC dc;
3868 PDC_ATTR Dc_Attr;
3869 PTEXTOBJ TextObj;
3870 PFONTGDI FontGDI;
3871 FT_Face face;
3872 FT_CharMap charmap, found = NULL;
3873 UINT i, glyph_index, BufferSize;
3874 HFONT hFont = 0;
3875
3876 if(pwc)
3877 {
3878 _SEH_TRY
3879 {
3880 ProbeForRead(pwc,
3881 sizeof(PWSTR),
3882 1);
3883 }
3884 _SEH_HANDLE
3885 {
3886 Status = _SEH_GetExceptionCode();
3887 }
3888 _SEH_END;
3889 }
3890 if (!NT_SUCCESS(Status))
3891 {
3892 SetLastWin32Error(Status);
3893 return FALSE;
3894 }
3895
3896 BufferSize = Count * sizeof(INT); // Same size!
3897 SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
3898 if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
3899 if (SafeBuff == NULL)
3900 {
3901 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3902 return FALSE;
3903 }
3904
3905 dc = DC_LockDc(hDC);
3906 if (dc == NULL)
3907 {
3908 ExFreePool(SafeBuff);
3909 SetLastWin32Error(ERROR_INVALID_HANDLE);
3910 return FALSE;
3911 }
3912 Dc_Attr = dc->pDc_Attr;
3913 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
3914 hFont = Dc_Attr->hlfntNew;
3915 TextObj = RealizeFontInit(hFont);
3916 DC_UnlockDc(dc);
3917
3918 if (TextObj == NULL)
3919 {
3920 ExFreePool(SafeBuff);
3921 SetLastWin32Error(ERROR_INVALID_HANDLE);
3922 return FALSE;
3923 }
3924
3925 FontGDI = ObjToGDI(TextObj->Font, FONT);
3926
3927 face = FontGDI->face;
3928 if (face->charmap == NULL)
3929 {
3930 for (i = 0; i < face->num_charmaps; i++)
3931 {
3932 charmap = face->charmaps[i];
3933 if (charmap->encoding != 0)
3934 {
3935 found = charmap;
3936 break;
3937 }
3938 }
3939
3940 if (!found)
3941 {
3942 DPRINT1("WARNING: Could not find desired charmap!\n");
3943 ExFreePool(SafeBuff);
3944 SetLastWin32Error(ERROR_INVALID_HANDLE);
3945 return FALSE;
3946 }
3947
3948 IntLockFreeType;
3949 FT_Set_Charmap(face, found);
3950 IntUnLockFreeType;
3951 }
3952
3953 IntLockFreeType;
3954 FT_Set_Pixel_Sizes(face,
3955 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
3956 /* FIXME should set character height if neg */
3957 (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
3958 - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
3959 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
3960
3961 for (i = FirstChar; i < FirstChar+Count; i++)
3962 {
3963 if (pwc)
3964 {
3965 if (fl & GCW_INDICES)
3966 glyph_index = pwc[i - FirstChar];
3967 else
3968 glyph_index = FT_Get_Char_Index(face, pwc[i - FirstChar]);
3969 }
3970 else
3971 {
3972 if (fl & GCW_INDICES)
3973 glyph_index = i;
3974 else
3975 glyph_index = FT_Get_Char_Index(face, i);
3976 }
3977 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3978 if (!fl)
3979 SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
3980 else
3981 SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
3982 }
3983 IntUnLockFreeType;
3984 TEXTOBJ_UnlockText(TextObj);
3985 MmCopyToCaller(Buffer, SafeBuff, BufferSize);
3986 ExFreePool(SafeBuff);
3987 return TRUE;
3988 }
3989
3990
3991 /*
3992 * @implemented
3993 */
3994 DWORD
3995 STDCALL
3996 NtGdiGetGlyphIndicesW(
3997 IN HDC hdc,
3998 IN OPTIONAL LPWSTR UnSafepwc,
3999 IN INT cwc,
4000 OUT OPTIONAL LPWORD UnSafepgi,
4001 IN DWORD iMode)
4002 {
4003 PDC dc;
4004 PDC_ATTR Dc_Attr;
4005 PTEXTOBJ TextObj;
4006 PFONTGDI FontGDI;
4007 HFONT hFont = 0;
4008 NTSTATUS Status = STATUS_SUCCESS;
4009 OUTLINETEXTMETRICW *potm;
4010 INT i;
4011 FT_Face face;
4012 WCHAR DefChar = 0xffff;
4013 PWSTR Buffer = NULL;
4014 ULONG Size;
4015
4016 if ((!UnSafepwc) && (!UnSafepgi)) return cwc;
4017
4018 dc = DC_LockDc(hdc);
4019 if (!dc)
4020 {
4021 SetLastWin32Error(ERROR_INVALID_HANDLE);
4022 return GDI_ERROR;
4023 }
4024 Dc_Attr = dc->pDc_Attr;
4025 if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
4026 hFont = Dc_Attr->hlfntNew;
4027 TextObj = RealizeFontInit(hFont);
4028 DC_UnlockDc(dc);
4029 if (!TextObj)
4030 {
4031 SetLastWin32Error(ERROR_INVALID_HANDLE);
4032 return GDI_ERROR;
4033 }
4034
4035 FontGDI = ObjToGDI(TextObj->Font, FONT);
4036 TEXTOBJ_UnlockText(TextObj);
4037
4038 Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), TAG_GDITEXT);
4039 if (!Buffer)
4040 {
4041 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
4042 return GDI_ERROR;
4043 }
4044
4045 if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f; /* Indicate non existence */
4046 else
4047 {
4048 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
4049 potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
4050 if (!potm)
4051 {
4052 Status = ERROR_NOT_ENOUGH_MEMORY;
4053 goto ErrorRet;
4054 }
4055 IntGetOutlineTextMetrics(FontGDI, Size, potm);
4056 DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
4057 ExFreePool(potm);
4058 }
4059
4060 _SEH_TRY
4061 {
4062 ProbeForRead(UnSafepwc,
4063 sizeof(PWSTR),
4064 1);
4065 }
4066 _SEH_HANDLE
4067 {
4068 Status = _SEH_GetExceptionCode();
4069 }
4070 _SEH_END;
4071
4072 if (!NT_SUCCESS(Status)) goto ErrorRet;
4073
4074 IntLockFreeType;
4075 face = FontGDI->face;
4076
4077 for (i = 0; i < cwc; i++)
4078 {
4079 Buffer[i] = FT_Get_Char_Index(face, UnSafepwc[i]);
4080 if (Buffer[i] == 0)
4081 {
4082 if (DefChar == 0xffff && FT_IS_SFNT(face))
4083 {
4084 TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
4085 DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0);
4086 }
4087 Buffer[i] = DefChar;
4088 }
4089 }
4090
4091 IntUnLockFreeType;
4092
4093 _SEH_TRY
4094 {
4095 ProbeForWrite(UnSafepgi,
4096 sizeof(WORD),
4097 1);
4098 RtlCopyMemory(UnSafepgi,
4099 Buffer,
4100 cwc*sizeof(WORD));
4101 }
4102 _SEH_HANDLE
4103 {
4104 Status = _SEH_GetExceptionCode();
4105 }
4106 _SEH_END;
4107
4108 ErrorRet:
4109 ExFreePoolWithTag(Buffer, TAG_GDITEXT);
4110 if (NT_SUCCESS(Status)) return cwc;
4111 SetLastWin32Error(Status);
4112 return GDI_ERROR;
4113 }
4114
4115
4116 /* EOF */