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