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