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