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