Copy makefile
[reactos.git] / reactos / subsys / win32k / objects / text.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * Parts based on Wine code
6 * Copyright 1993 Alexandre Julliard
7 * 1997 Alex Korobka
8 * Copyright 2002,2003 Shachar Shemesh
9 * Copyright 2001 Huw D M Davies for CodeWeavers.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25 /* $Id$ */
26 #include <w32k.h>
27
28 #include <ft2build.h>
29 #include FT_FREETYPE_H
30 #include <freetype/tttables.h>
31
32 FT_Library library;
33
34 typedef struct _FONT_ENTRY {
35 LIST_ENTRY ListEntry;
36 FONTGDI *Font;
37 UNICODE_STRING FaceName;
38 BYTE NotEnum;
39 } FONT_ENTRY, *PFONT_ENTRY;
40
41 /* The FreeType library is not thread safe, so we have
42 to serialize access to it */
43 static FAST_MUTEX FreeTypeLock;
44
45 static LIST_ENTRY FontListHead;
46 static FAST_MUTEX FontListLock;
47 static BOOL RenderingEnabled = TRUE;
48
49 static PWCHAR ElfScripts[32] = { /* these are in the order of the fsCsb[0] bits */
50 L"Western", /*00*/
51 L"Central_European",
52 L"Cyrillic",
53 L"Greek",
54 L"Turkish",
55 L"Hebrew",
56 L"Arabic",
57 L"Baltic",
58 L"Vietnamese", /*08*/
59 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
60 L"Thai",
61 L"Japanese",
62 L"CHINESE_GB2312",
63 L"Hangul",
64 L"CHINESE_BIG5",
65 L"Hangul(Johab)",
66 NULL, NULL, /*23*/
67 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
68 L"Symbol" /*31*/
69 };
70
71 /*
72 * For NtGdiTranslateCharsetInfo
73 */
74 #define FS(x) {{0,0,0,0},{0x1<<(x),0}}
75 #define MAXTCIINDEX 32
76 static CHARSETINFO FontTci[MAXTCIINDEX] = {
77 /* ANSI */
78 { ANSI_CHARSET, 1252, FS(0)},
79 { EASTEUROPE_CHARSET, 1250, FS(1)},
80 { RUSSIAN_CHARSET, 1251, FS(2)},
81 { GREEK_CHARSET, 1253, FS(3)},
82 { TURKISH_CHARSET, 1254, FS(4)},
83 { HEBREW_CHARSET, 1255, FS(5)},
84 { ARABIC_CHARSET, 1256, FS(6)},
85 { BALTIC_CHARSET, 1257, FS(7)},
86 { VIETNAMESE_CHARSET, 1258, FS(8)},
87 /* reserved by ANSI */
88 { DEFAULT_CHARSET, 0, FS(0)},
89 { DEFAULT_CHARSET, 0, FS(0)},
90 { DEFAULT_CHARSET, 0, FS(0)},
91 { DEFAULT_CHARSET, 0, FS(0)},
92 { DEFAULT_CHARSET, 0, FS(0)},
93 { DEFAULT_CHARSET, 0, FS(0)},
94 { DEFAULT_CHARSET, 0, FS(0)},
95 /* ANSI and OEM */
96 { THAI_CHARSET, 874, FS(16)},
97 { SHIFTJIS_CHARSET, 932, FS(17)},
98 { GB2312_CHARSET, 936, FS(18)},
99 { HANGEUL_CHARSET, 949, FS(19)},
100 { CHINESEBIG5_CHARSET, 950, FS(20)},
101 { JOHAB_CHARSET, 1361, FS(21)},
102 /* reserved for alternate ANSI and OEM */
103 { DEFAULT_CHARSET, 0, FS(0)},
104 { DEFAULT_CHARSET, 0, FS(0)},
105 { DEFAULT_CHARSET, 0, FS(0)},
106 { DEFAULT_CHARSET, 0, FS(0)},
107 { DEFAULT_CHARSET, 0, FS(0)},
108 { DEFAULT_CHARSET, 0, FS(0)},
109 { DEFAULT_CHARSET, 0, FS(0)},
110 { DEFAULT_CHARSET, 0, FS(0)},
111 /* reserved for system */
112 { DEFAULT_CHARSET, 0, FS(0)},
113 { SYMBOL_CHARSET, CP_SYMBOL, FS(31)},
114 };
115
116 VOID FASTCALL
117 IntLoadSystemFonts(VOID);
118
119 INT FASTCALL
120 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics);
121
122 BOOL FASTCALL
123 InitFontSupport(VOID)
124 {
125 ULONG ulError;
126
127 InitializeListHead(&FontListHead);
128 ExInitializeFastMutex(&FontListLock);
129 ExInitializeFastMutex(&FreeTypeLock);
130
131 ulError = FT_Init_FreeType(&library);
132 if (ulError) {
133 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
134 return FALSE;
135 }
136
137 IntLoadSystemFonts();
138
139 return TRUE;
140 }
141
142 /*
143 * IntLoadSystemFonts
144 *
145 * Search the system font directory and adds each font found.
146 */
147
148 VOID FASTCALL
149 IntLoadSystemFonts(VOID)
150 {
151 OBJECT_ATTRIBUTES ObjectAttributes;
152 UNICODE_STRING Directory, SearchPattern, FileName, TempString;
153 IO_STATUS_BLOCK Iosb;
154 HANDLE hDirectory;
155 BYTE *DirInfoBuffer;
156 PFILE_DIRECTORY_INFORMATION DirInfo;
157 BOOL bRestartScan = TRUE;
158 NTSTATUS Status;
159
160 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\media\\fonts\\");
161 /* FIXME: Add support for other font types */
162 RtlInitUnicodeString(&SearchPattern, L"*.ttf");
163
164 InitializeObjectAttributes(
165 &ObjectAttributes,
166 &Directory,
167 OBJ_CASE_INSENSITIVE,
168 NULL,
169 NULL);
170
171 Status = ZwOpenFile(
172 &hDirectory,
173 SYNCHRONIZE | FILE_LIST_DIRECTORY,
174 &ObjectAttributes,
175 &Iosb,
176 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
177 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
178
179 if (NT_SUCCESS(Status))
180 {
181 DirInfoBuffer = ExAllocatePool(PagedPool, 0x4000);
182 if (DirInfoBuffer == NULL)
183 {
184 ZwClose(hDirectory);
185 return;
186 }
187
188 FileName.Buffer = ExAllocatePool(PagedPool, MAX_PATH);
189 if (FileName.Buffer == NULL)
190 {
191 ExFreePool(DirInfoBuffer);
192 ZwClose(hDirectory);
193 return;
194 }
195 FileName.Length = 0;
196 FileName.MaximumLength = MAX_PATH;
197
198 while (1)
199 {
200 Status = ZwQueryDirectoryFile(
201 hDirectory,
202 NULL,
203 NULL,
204 NULL,
205 &Iosb,
206 DirInfoBuffer,
207 0x4000,
208 FileDirectoryInformation,
209 FALSE,
210 &SearchPattern,
211 bRestartScan);
212
213 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
214 {
215 break;
216 }
217
218 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
219 while (1)
220 {
221 TempString.Buffer = DirInfo->FileName;
222 TempString.Length =
223 TempString.MaximumLength = DirInfo->FileNameLength;
224 RtlCopyUnicodeString(&FileName, &Directory);
225 RtlAppendUnicodeStringToString(&FileName, &TempString);
226 IntGdiAddFontResource(&FileName, 0);
227 if (DirInfo->NextEntryOffset == 0)
228 break;
229 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
230 }
231
232 bRestartScan = FALSE;
233 }
234
235 ExFreePool(FileName.Buffer);
236 ExFreePool(DirInfoBuffer);
237 ZwClose(hDirectory);
238 }
239 }
240
241 /*
242 * IntGdiAddFontResource
243 *
244 * Adds the font resource from the specified file to the system.
245 */
246
247 INT FASTCALL
248 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
249 {
250 FONTGDI *FontGDI;
251 NTSTATUS Status;
252 HANDLE FileHandle;
253 OBJECT_ATTRIBUTES ObjectAttributes;
254 FILE_STANDARD_INFORMATION FileStdInfo;
255 PVOID Buffer;
256 IO_STATUS_BLOCK Iosb;
257 INT Error;
258 FT_Face Face;
259 ANSI_STRING AnsiFaceName;
260 PFONT_ENTRY Entry;
261
262 /* Open the font file */
263
264 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
265 Status = ZwOpenFile(
266 &FileHandle,
267 GENERIC_READ | SYNCHRONIZE,
268 &ObjectAttributes,
269 &Iosb,
270 0,
271 FILE_SYNCHRONOUS_IO_NONALERT);
272
273 if (!NT_SUCCESS(Status))
274 {
275 DPRINT("Could not font file: %wZ\n", FileName);
276 return 0;
277 }
278
279 /* Get the size of the file */
280
281 Status = NtQueryInformationFile(
282 FileHandle,
283 &Iosb,
284 &FileStdInfo,
285 sizeof(FileStdInfo),
286 FileStandardInformation);
287
288 if (!NT_SUCCESS(Status))
289 {
290 DPRINT("Could not get file size\n");
291 ZwClose(FileHandle);
292 return 0;
293 }
294
295 /* Allocate pageable memory for the font */
296
297 Buffer = ExAllocatePoolWithTag(
298 PagedPool,
299 FileStdInfo.EndOfFile.u.LowPart,
300 TAG_FNTFILE);
301
302 if (Buffer == NULL)
303 {
304 DPRINT("Could not allocate memory for font");
305 ZwClose(FileHandle);
306 return 0;
307 }
308
309 /* Load the font into memory chunk */
310
311 Status = ZwReadFile(
312 FileHandle,
313 NULL,
314 NULL,
315 NULL,
316 &Iosb,
317 Buffer,
318 FileStdInfo.EndOfFile.u.LowPart,
319 NULL,
320 NULL);
321
322 if (!NT_SUCCESS(Status))
323 {
324 DPRINT("Could not read the font file into memory");
325 ExFreePool(Buffer);
326 ZwClose(FileHandle);
327 return 0;
328 }
329
330 ZwClose(FileHandle);
331
332 IntLockFreeType;
333 Error = FT_New_Memory_Face(
334 library,
335 Buffer,
336 FileStdInfo.EndOfFile.u.LowPart,
337 0,
338 &Face);
339 IntUnLockFreeType;
340
341 if (Error)
342 {
343 if (Error == FT_Err_Unknown_File_Format)
344 DPRINT("Unknown font file format\n");
345 else
346 DPRINT("Error reading font file (error code: %u)\n", Error);
347 ExFreePool(Buffer);
348 return 0;
349 }
350
351 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
352 if (!Entry)
353 {
354 FT_Done_Face(Face);
355 ExFreePool(Buffer);
356 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
357 return 0;
358 }
359
360 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), TAG_FONTOBJ);
361 if(FontGDI == NULL)
362 {
363 FT_Done_Face(Face);
364 ExFreePool(Buffer);
365 ExFreePool(Entry);
366 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
367 return 0;
368 }
369
370 /* FontGDI->Filename = FileName; perform strcpy */
371 FontGDI->face = Face;
372
373 /* FIXME: Complete text metrics */
374 FontGDI->TextMetric.tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
375 FontGDI->TextMetric.tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
376 FontGDI->TextMetric.tmHeight = (Face->size->metrics.ascender -
377 Face->size->metrics.descender) >> 6;
378
379 DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
380 DPRINT("Num glyphs: %u\n", Face->num_glyphs);
381
382 /* Add this font resource to the font table */
383
384 Entry->Font = FontGDI;
385 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
386 RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name);
387 RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
388
389 if (Characteristics & FR_PRIVATE)
390 {
391 PW32PROCESS Win32Process = PsGetWin32Process();
392 IntLockProcessPrivateFonts(Win32Process);
393 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
394 IntUnLockProcessPrivateFonts(Win32Process);
395 }
396 else
397 {
398 IntLockGlobalFonts;
399 InsertTailList(&FontListHead, &Entry->ListEntry);
400 IntUnLockGlobalFonts;
401 }
402
403 return 1;
404 }
405
406 BOOL FASTCALL
407 IntIsFontRenderingEnabled(VOID)
408 {
409 BOOL Ret = RenderingEnabled;
410 HDC hDC;
411
412 hDC = IntGetScreenDC();
413 if (hDC)
414 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
415
416 return Ret;
417 }
418
419 VOID FASTCALL
420 IntEnableFontRendering(BOOL Enable)
421 {
422 RenderingEnabled = Enable;
423 }
424
425 FT_Render_Mode FASTCALL
426 IntGetFontRenderMode(LOGFONTW *logfont)
427 {
428 switch(logfont->lfQuality)
429 {
430 //case ANTIALIASED_QUALITY:
431 case DEFAULT_QUALITY:
432 return FT_RENDER_MODE_NORMAL;
433 case DRAFT_QUALITY:
434 return FT_RENDER_MODE_LIGHT;
435 //case NONANTIALIASED_QUALITY:
436 case PROOF_QUALITY:
437 return FT_RENDER_MODE_MONO;
438 //case CLEARTYPE_QUALITY:
439 // return FT_RENDER_MODE_LCD;
440 }
441 return FT_RENDER_MODE_MONO;
442 }
443
444 int
445 STDCALL
446 NtGdiAddFontResource(PUNICODE_STRING Filename, DWORD fl)
447 {
448 UNICODE_STRING SafeFileName;
449 PWSTR src;
450 NTSTATUS Status;
451 int Ret;
452
453 /* Copy the UNICODE_STRING structure */
454 Status = MmCopyFromCaller(&SafeFileName, Filename, sizeof(UNICODE_STRING));
455 if(!NT_SUCCESS(Status))
456 {
457 SetLastNtError(Status);
458 return 0;
459 }
460
461 /* Reserve for prepending '\??\' */
462 SafeFileName.Length += 4 * sizeof(WCHAR);
463 SafeFileName.MaximumLength += 4 * sizeof(WCHAR);
464
465 src = SafeFileName.Buffer;
466 SafeFileName.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, SafeFileName.MaximumLength, TAG_STRING);
467 if(!SafeFileName.Buffer)
468 {
469 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
470 return 0;
471 }
472
473 /* Prepend '\??\' */
474 RtlCopyMemory(SafeFileName.Buffer, L"\\??\\", 4 * sizeof(WCHAR));
475
476 Status = MmCopyFromCaller(SafeFileName.Buffer + 4, src, SafeFileName.MaximumLength - (4 * sizeof(WCHAR)));
477 if(!NT_SUCCESS(Status))
478 {
479 ExFreePool(SafeFileName.Buffer);
480 SetLastNtError(Status);
481 return 0;
482 }
483
484 Ret = IntGdiAddFontResource(&SafeFileName, fl);
485
486 ExFreePool(SafeFileName.Buffer);
487 return Ret;
488 }
489
490 NTSTATUS FASTCALL
491 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
492 {
493 PTEXTOBJ TextObj;
494 NTSTATUS Status = STATUS_SUCCESS;
495
496 *NewFont = TEXTOBJ_AllocText();
497 if (NULL != *NewFont)
498 {
499 TextObj = TEXTOBJ_LockText(*NewFont);
500 if (NULL != TextObj)
501 {
502 memcpy(&TextObj->logfont, lf, sizeof(LOGFONTW));
503 if (lf->lfEscapement != lf->lfOrientation)
504 {
505 /* this should really depend on whether GM_ADVANCED is set */
506 TextObj->logfont.lfOrientation = TextObj->logfont.lfEscapement;
507 }
508 TEXTOBJ_UnlockText(*NewFont);
509 }
510 else
511 {
512 /* FIXME */
513 /* ASSERT(FALSE);*/
514 Status = STATUS_INVALID_HANDLE;
515 }
516 }
517 else
518 {
519 Status = STATUS_NO_MEMORY;
520 }
521
522 return Status;
523 }
524
525 HFONT
526 STDCALL
527 NtGdiCreateFont(int Height,
528 int Width,
529 int Escapement,
530 int Orientation,
531 int Weight,
532 DWORD Italic,
533 DWORD Underline,
534 DWORD StrikeOut,
535 DWORD CharSet,
536 DWORD OutputPrecision,
537 DWORD ClipPrecision,
538 DWORD Quality,
539 DWORD PitchAndFamily,
540 LPCWSTR Face)
541 {
542 LOGFONTW logfont;
543 HFONT NewFont;
544 NTSTATUS Status = STATUS_SUCCESS;
545
546 logfont.lfHeight = Height;
547 logfont.lfWidth = Width;
548 logfont.lfEscapement = Escapement;
549 logfont.lfOrientation = Orientation;
550 logfont.lfWeight = Weight;
551 logfont.lfItalic = Italic;
552 logfont.lfUnderline = Underline;
553 logfont.lfStrikeOut = StrikeOut;
554 logfont.lfCharSet = CharSet;
555 logfont.lfOutPrecision = OutputPrecision;
556 logfont.lfClipPrecision = ClipPrecision;
557 logfont.lfQuality = Quality;
558 logfont.lfPitchAndFamily = PitchAndFamily;
559
560 if (NULL != Face)
561 {
562 int Size = sizeof(logfont.lfFaceName) / sizeof(WCHAR);
563 wcsncpy((wchar_t *)logfont.lfFaceName, Face, Size - 1);
564 /* Be 101% sure to have '\0' at end of string */
565 logfont.lfFaceName[Size - 1] = '\0';
566 }
567 else
568 {
569 logfont.lfFaceName[0] = L'\0';
570 }
571
572 if (NT_SUCCESS(Status))
573 {
574 Status = TextIntCreateFontIndirect(&logfont, &NewFont);
575 }
576
577 return NT_SUCCESS(Status) ? NewFont : NULL;
578 }
579
580 HFONT
581 STDCALL
582 NtGdiCreateFontIndirect(CONST LPLOGFONTW lf)
583 {
584 LOGFONTW SafeLogfont;
585 HFONT NewFont;
586 NTSTATUS Status = STATUS_SUCCESS;
587
588 if (NULL != lf)
589 {
590 Status = MmCopyFromCaller(&SafeLogfont, lf, sizeof(LOGFONTW));
591 if (NT_SUCCESS(Status))
592 {
593 Status = TextIntCreateFontIndirect(&SafeLogfont, &NewFont);
594 }
595 }
596 else
597 {
598 Status = STATUS_INVALID_PARAMETER;
599 }
600
601 return NT_SUCCESS(Status) ? NewFont : NULL;
602 }
603
604 BOOL
605 STDCALL
606 NtGdiCreateScalableFontResource(DWORD Hidden,
607 LPCWSTR FontRes,
608 LPCWSTR FontFile,
609 LPCWSTR CurrentPath)
610 {
611 DPRINT1("NtGdiCreateScalableFontResource - is unimplemented, have a nice day and keep going");
612 return FALSE;
613 }
614
615 /*************************************************************************
616 * TranslateCharsetInfo
617 *
618 * Fills a CHARSETINFO structure for a character set, code page, or
619 * font. This allows making the correspondance between different labelings
620 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
621 * of the same encoding.
622 *
623 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
624 * only one codepage should be set in *Src.
625 *
626 * RETURNS
627 * TRUE on success, FALSE on failure.
628 *
629 */
630 static BOOLEAN STDCALL
631 IntTranslateCharsetInfo(PDWORD Src, /* [in]
632 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
633 if flags == TCI_SRCCHARSET: a character set value
634 if flags == TCI_SRCCODEPAGE: a code page value */
635 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
636 DWORD Flags /* [in] determines interpretation of lpSrc */)
637 {
638 int Index = 0;
639
640 switch (Flags)
641 {
642 case TCI_SRCFONTSIG:
643 while (0 == (*Src >> Index & 0x0001) && Index < MAXTCIINDEX)
644 {
645 Index++;
646 }
647 break;
648 case TCI_SRCCODEPAGE:
649 while ((UINT) (Src) != FontTci[Index].ciACP && Index < MAXTCIINDEX)
650 {
651 Index++;
652 }
653 break;
654 case TCI_SRCCHARSET:
655 while ((UINT) (Src) != FontTci[Index].ciCharset && Index < MAXTCIINDEX)
656 {
657 Index++;
658 }
659 break;
660 default:
661 return FALSE;
662 }
663
664 if (MAXTCIINDEX <= Index || DEFAULT_CHARSET == FontTci[Index].ciCharset)
665 {
666 return FALSE;
667 }
668
669 memcpy(Cs, &FontTci[Index], sizeof(CHARSETINFO));
670
671 return TRUE;
672 }
673
674 BOOL STDCALL
675 NtGdiTranslateCharsetInfo(PDWORD Src,
676 LPCHARSETINFO UnsafeCs,
677 DWORD Flags)
678 {
679 CHARSETINFO Cs;
680 BOOLEAN Ret;
681 NTSTATUS Status;
682
683 Ret = IntTranslateCharsetInfo(Src, &Cs, Flags);
684 if (Ret)
685 {
686 Status = MmCopyToCaller(UnsafeCs, &Cs, sizeof(CHARSETINFO));
687 if (! NT_SUCCESS(Status))
688 {
689 SetLastWin32Error(ERROR_INVALID_PARAMETER);
690 return FALSE;
691 }
692 }
693
694 return (BOOL) Ret;
695 }
696
697 static void FASTCALL
698 FillTM(TEXTMETRICW *TM, FT_Face Face, TT_OS2 *pOS2, TT_HoriHeader *pHori)
699 {
700 FT_Fixed XScale, YScale;
701 int Ascent, Descent;
702
703 XScale = Face->size->metrics.x_scale;
704 YScale = Face->size->metrics.y_scale;
705
706 if (0 == pOS2->usWinAscent + pOS2->usWinDescent)
707 {
708 Ascent = pHori->Ascender;
709 Descent = -pHori->Descender;
710 }
711 else
712 {
713 Ascent = pOS2->usWinAscent;
714 Descent = pOS2->usWinDescent;
715 }
716
717 #if 0 /* This (Wine) code doesn't seem to work correctly for us */
718 TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
719 TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
720 #else
721 TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
722 TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
723 #endif
724 TM->tmInternalLeading = (FT_MulFix(Ascent + Descent
725 - Face->units_per_EM, YScale) + 32) >> 6;
726
727 TM->tmHeight = TM->tmAscent + TM->tmDescent;
728
729 /* MSDN says:
730 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
731 */
732 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
733 - ((Ascent + Descent)
734 - (pHori->Ascender - pHori->Descender)),
735 YScale) + 32) >> 6);
736
737 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
738 if (0 == TM->tmAveCharWidth)
739 {
740 TM->tmAveCharWidth = 1;
741 }
742 TM->tmMaxCharWidth = (FT_MulFix(Face->bbox.xMax - Face->bbox.xMin,
743 XScale) + 32) >> 6;
744 TM->tmWeight = pOS2->usWeightClass;
745 TM->tmOverhang = 0;
746 TM->tmDigitizedAspectX = 300;
747 TM->tmDigitizedAspectY = 300;
748 TM->tmFirstChar = pOS2->usFirstCharIndex;
749 TM->tmLastChar = pOS2->usLastCharIndex;
750 TM->tmDefaultChar = pOS2->usDefaultChar;
751 TM->tmBreakChar = L'\0' != pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
752 TM->tmItalic = (Face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0;
753 TM->tmUnderlined = 0; /* entry in OS2 table */
754 TM->tmStruckOut = 0; /* entry in OS2 table */
755
756 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
757 if (! FT_IS_FIXED_WIDTH(Face))
758 {
759 TM->tmPitchAndFamily = TMPF_FIXED_PITCH;
760 }
761 else
762 {
763 TM->tmPitchAndFamily = 0;
764 }
765
766 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
767 {
768 case PAN_FAMILY_SCRIPT:
769 TM->tmPitchAndFamily |= FF_SCRIPT;
770 break;
771 case PAN_FAMILY_DECORATIVE:
772 case PAN_FAMILY_PICTORIAL:
773 TM->tmPitchAndFamily |= FF_DECORATIVE;
774 break;
775 case PAN_FAMILY_TEXT_DISPLAY:
776 if (0 == TM->tmPitchAndFamily) /* fixed */
777 {
778 TM->tmPitchAndFamily = FF_MODERN;
779 }
780 else
781 {
782 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
783 {
784 case PAN_SERIF_NORMAL_SANS:
785 case PAN_SERIF_OBTUSE_SANS:
786 case PAN_SERIF_PERP_SANS:
787 TM->tmPitchAndFamily |= FF_SWISS;
788 break;
789 default:
790 TM->tmPitchAndFamily |= FF_ROMAN;
791 break;
792 }
793 }
794 break;
795 default:
796 TM->tmPitchAndFamily |= FF_DONTCARE;
797 }
798
799 if (FT_IS_SCALABLE(Face))
800 {
801 TM->tmPitchAndFamily |= TMPF_VECTOR;
802 }
803 if (FT_IS_SFNT(Face))
804 {
805 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
806 }
807
808 TM->tmCharSet = DEFAULT_CHARSET;
809 }
810
811 /*************************************************************
812 * IntGetOutlineTextMetrics
813 *
814 */
815 static unsigned FASTCALL
816 IntGetOutlineTextMetrics(PFONTGDI FontGDI, UINT Size,
817 OUTLINETEXTMETRICW *Otm)
818 {
819 unsigned Needed;
820 TT_OS2 *pOS2;
821 TT_HoriHeader *pHori;
822 TT_Postscript *pPost;
823 FT_Fixed XScale, YScale;
824 ANSI_STRING FamilyNameA, StyleNameA;
825 UNICODE_STRING FamilyNameW, StyleNameW, Regular;
826 char *Cp;
827
828 Needed = sizeof(OUTLINETEXTMETRICW);
829
830 RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name);
831 RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
832
833 RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name);
834 RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
835
836 /* These names should be read from the TT name table */
837
838 /* length of otmpFamilyName */
839 Needed += FamilyNameW.Length + sizeof(WCHAR);
840
841 RtlInitUnicodeString(&Regular, L"regular");
842 /* length of otmpFaceName */
843 if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
844 {
845 Needed += FamilyNameW.Length + sizeof(WCHAR); /* just the family name */
846 }
847 else
848 {
849 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
850 }
851
852 /* length of otmpStyleName */
853 Needed += StyleNameW.Length + sizeof(WCHAR);
854
855 /* length of otmpFullName */
856 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
857
858 if (Size < Needed)
859 {
860 RtlFreeUnicodeString(&FamilyNameW);
861 RtlFreeUnicodeString(&StyleNameW);
862 return Needed;
863 }
864
865 XScale = FontGDI->face->size->metrics.x_scale;
866 YScale = FontGDI->face->size->metrics.y_scale;
867
868 IntLockFreeType;
869 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
870 if (NULL == pOS2)
871 {
872 IntUnLockFreeType;
873 DPRINT1("Can't find OS/2 table - not TT font?\n");
874 RtlFreeUnicodeString(&StyleNameW);
875 RtlFreeUnicodeString(&FamilyNameW);
876 return 0;
877 }
878
879 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
880 if (NULL == pHori)
881 {
882 IntUnLockFreeType;
883 DPRINT1("Can't find HHEA table - not TT font?\n");
884 RtlFreeUnicodeString(&StyleNameW);
885 RtlFreeUnicodeString(&FamilyNameW);
886 return 0;
887 }
888
889 pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* we can live with this failing */
890
891 Otm->otmSize = Needed;
892
893 FillTM(&Otm->otmTextMetrics, FontGDI->face, pOS2, pHori);
894
895 Otm->otmFiller = 0;
896 memcpy(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
897 Otm->otmfsSelection = pOS2->fsSelection;
898 Otm->otmfsType = pOS2->fsType;
899 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
900 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
901 Otm->otmItalicAngle = 0; /* POST table */
902 Otm->otmEMSquare = FontGDI->face->units_per_EM;
903 Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
904 Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
905 Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
906 Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
907 Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
908 Otm->otmrcFontBox.left = (FT_MulFix(FontGDI->face->bbox.xMin, XScale) + 32) >> 6;
909 Otm->otmrcFontBox.right = (FT_MulFix(FontGDI->face->bbox.xMax, XScale) + 32) >> 6;
910 Otm->otmrcFontBox.top = (FT_MulFix(FontGDI->face->bbox.yMax, YScale) + 32) >> 6;
911 Otm->otmrcFontBox.bottom = (FT_MulFix(FontGDI->face->bbox.yMin, YScale) + 32) >> 6;
912 Otm->otmMacAscent = 0; /* where do these come from ? */
913 Otm->otmMacDescent = 0;
914 Otm->otmMacLineGap = 0;
915 Otm->otmusMinimumPPEM = 0; /* TT Header */
916 Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
917 Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
918 Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
919 Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
920 Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
921 Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
922 Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
923 Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
924 Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
925 Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
926 if (NULL == pPost)
927 {
928 Otm->otmsUnderscoreSize = 0;
929 Otm->otmsUnderscorePosition = 0;
930 }
931 else
932 {
933 Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
934 Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
935 }
936
937 IntUnLockFreeType;
938
939 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
940 Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
941 Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
942 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
943 Cp += FamilyNameW.Length + sizeof(WCHAR);
944 Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
945 wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
946 Cp += StyleNameW.Length + sizeof(WCHAR);
947 Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
948 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
949 if (0 != RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
950 {
951 wcscat((WCHAR*) Cp, L" ");
952 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
953 Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
954 }
955 else
956 {
957 Cp += FamilyNameW.Length + sizeof(WCHAR);
958 }
959 Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
960 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
961 wcscat((WCHAR*) Cp, L" ");
962 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
963
964 RtlFreeUnicodeString(&StyleNameW);
965 RtlFreeUnicodeString(&FamilyNameW);
966
967 return Needed;
968 }
969
970 static PFONTGDI FASTCALL
971 FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
972 {
973 PLIST_ENTRY Entry;
974 PFONT_ENTRY CurrentEntry;
975 ANSI_STRING EntryFaceNameA;
976 UNICODE_STRING EntryFaceNameW;
977 FONTGDI *FontGDI;
978
979 Entry = Head->Flink;
980 while (Entry != Head)
981 {
982 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
983
984 FontGDI = CurrentEntry->Font;
985 ASSERT(FontGDI);
986
987 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
988 RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
989 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
990 {
991 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
992 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
993 }
994
995 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
996 {
997 RtlFreeUnicodeString(&EntryFaceNameW);
998 return FontGDI;
999 }
1000
1001 RtlFreeUnicodeString(&EntryFaceNameW);
1002 Entry = Entry->Flink;
1003 }
1004
1005 return NULL;
1006 }
1007
1008 static PFONTGDI FASTCALL
1009 FindFaceNameInLists(PUNICODE_STRING FaceName)
1010 {
1011 PW32PROCESS Win32Process;
1012 PFONTGDI Font;
1013
1014 /* Search the process local list */
1015 Win32Process = PsGetWin32Process();
1016 IntLockProcessPrivateFonts(Win32Process);
1017 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
1018 IntUnLockProcessPrivateFonts(Win32Process);
1019 if (NULL != Font)
1020 {
1021 return Font;
1022 }
1023
1024 /* Search the global list */
1025 IntLockGlobalFonts;
1026 Font = FindFaceNameInList(FaceName, &FontListHead);
1027 IntUnLockGlobalFonts;
1028
1029 return Font;
1030 }
1031
1032 static void FASTCALL
1033 FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
1034 {
1035 ANSI_STRING StyleA;
1036 UNICODE_STRING StyleW;
1037 TT_OS2 *pOS2;
1038 FONTSIGNATURE fs;
1039 DWORD fs_fsCsb0;
1040 CHARSETINFO CharSetInfo;
1041 unsigned i, Size;
1042 OUTLINETEXTMETRICW *Otm;
1043 LOGFONTW *Lf;
1044 TEXTMETRICW *TM;
1045 NEWTEXTMETRICW *Ntm;
1046
1047 ZeroMemory(Info, sizeof(FONTFAMILYINFO));
1048 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
1049 Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
1050 if (NULL == Otm)
1051 {
1052 return;
1053 }
1054 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
1055
1056 Lf = &Info->EnumLogFontEx.elfLogFont;
1057 TM = &Otm->otmTextMetrics;
1058
1059 Lf->lfHeight = TM->tmHeight;
1060 Lf->lfWidth = TM->tmAveCharWidth;
1061 Lf->lfWeight = TM->tmWeight;
1062 Lf->lfItalic = TM->tmItalic;
1063 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
1064 Lf->lfCharSet = TM->tmCharSet;
1065 Lf->lfOutPrecision = OUT_STROKE_PRECIS;
1066 Lf->lfClipPrecision = CLIP_STROKE_PRECIS;
1067 Lf->lfQuality = DRAFT_QUALITY;
1068
1069 Ntm = &Info->NewTextMetricEx.ntmTm;
1070 Ntm->tmHeight = TM->tmHeight;
1071 Ntm->tmAscent = TM->tmAscent;
1072 Ntm->tmDescent = TM->tmDescent;
1073 Ntm->tmInternalLeading = TM->tmInternalLeading;
1074 Ntm->tmExternalLeading = TM->tmExternalLeading;
1075 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
1076 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
1077 Ntm->tmWeight = TM->tmWeight;
1078 Ntm->tmOverhang = TM->tmOverhang;
1079 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
1080 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
1081 Ntm->tmFirstChar = TM->tmFirstChar;
1082 Ntm->tmLastChar = TM->tmLastChar;
1083 Ntm->tmDefaultChar = TM->tmDefaultChar;
1084 Ntm->tmBreakChar = TM->tmBreakChar;
1085 Ntm->tmItalic = TM->tmItalic;
1086 Ntm->tmUnderlined = TM->tmUnderlined;
1087 Ntm->tmStruckOut = TM->tmStruckOut;
1088 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
1089 Ntm->tmCharSet = TM->tmCharSet;
1090 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
1091 if (550 < TM->tmWeight)
1092 {
1093 Ntm->ntmFlags |= NTM_BOLD;
1094 }
1095 if (0 == Ntm->ntmFlags)
1096 {
1097 Ntm->ntmFlags = NTM_REGULAR;
1098 }
1099
1100 Ntm->ntmSizeEM = Otm->otmEMSquare;
1101 Ntm->ntmCellHeight = 0;
1102 Ntm->ntmAvgWidth = 0;
1103
1104 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
1105 ? TRUETYPE_FONTTYPE : 0);
1106 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
1107 {
1108 Info->FontType |= RASTER_FONTTYPE;
1109 }
1110
1111 ExFreePool(Otm);
1112
1113 wcsncpy(Info->EnumLogFontEx.elfLogFont.lfFaceName, FaceName, LF_FACESIZE);
1114 wcsncpy(Info->EnumLogFontEx.elfFullName, FaceName, LF_FULLFACESIZE);
1115 RtlInitAnsiString(&StyleA, FontGDI->face->style_name);
1116 RtlAnsiStringToUnicodeString(&StyleW, &StyleA, TRUE);
1117 wcsncpy(Info->EnumLogFontEx.elfStyle, StyleW.Buffer, LF_FACESIZE);
1118 RtlFreeUnicodeString(&StyleW);
1119
1120 Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
1121 Info->EnumLogFontEx.elfScript[0] = L'\0';
1122 IntLockFreeType;
1123 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
1124 IntUnLockFreeType;
1125 if (NULL != pOS2)
1126 {
1127 Info->NewTextMetricEx.ntmFontSig.fsCsb[0] = pOS2->ulCodePageRange1;
1128 Info->NewTextMetricEx.ntmFontSig.fsCsb[1] = pOS2->ulCodePageRange2;
1129 Info->NewTextMetricEx.ntmFontSig.fsUsb[0] = pOS2->ulUnicodeRange1;
1130 Info->NewTextMetricEx.ntmFontSig.fsUsb[1] = pOS2->ulUnicodeRange2;
1131 Info->NewTextMetricEx.ntmFontSig.fsUsb[2] = pOS2->ulUnicodeRange3;
1132 Info->NewTextMetricEx.ntmFontSig.fsUsb[3] = pOS2->ulUnicodeRange4;
1133
1134 fs_fsCsb0 = pOS2->ulCodePageRange1;
1135 if (0 == pOS2->version)
1136 {
1137 FT_UInt Dummy;
1138
1139 if (FT_Get_First_Char(FontGDI->face, &Dummy) < 0x100)
1140 {
1141 fs_fsCsb0 |= 1;
1142 }
1143 else
1144 {
1145 fs_fsCsb0 |= 1L << 31;
1146 }
1147 }
1148 if (0 == fs_fsCsb0)
1149 { /* let's see if we can find any interesting cmaps */
1150 for (i = 0; i < FontGDI->face->num_charmaps; i++)
1151 {
1152 switch (FontGDI->face->charmaps[i]->encoding)
1153 {
1154 case ft_encoding_unicode:
1155 case ft_encoding_apple_roman:
1156 fs_fsCsb0 |= 1;
1157 break;
1158 case ft_encoding_symbol:
1159 fs_fsCsb0 |= 1L << 31;
1160 break;
1161 default:
1162 break;
1163 }
1164 }
1165 }
1166
1167 for(i = 0; i < 32; i++)
1168 {
1169 if (0 != (fs_fsCsb0 & (1L << i)))
1170 {
1171 fs.fsCsb[0] = 1L << i;
1172 fs.fsCsb[1] = 0;
1173 if (! IntTranslateCharsetInfo(fs.fsCsb, &CharSetInfo, TCI_SRCFONTSIG))
1174 {
1175 CharSetInfo.ciCharset = DEFAULT_CHARSET;
1176 }
1177 if (31 == i)
1178 {
1179 CharSetInfo.ciCharset = SYMBOL_CHARSET;
1180 }
1181 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
1182 {
1183 Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
1184 if (NULL != ElfScripts[i])
1185 {
1186 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
1187 }
1188 else
1189 {
1190 DPRINT1("Unknown elfscript for bit %d\n", i);
1191 }
1192 }
1193 }
1194 }
1195 }
1196 }
1197
1198 static int FASTCALL
1199 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
1200 {
1201 DWORD i;
1202 UNICODE_STRING InfoFaceName;
1203
1204 for (i = 0; i < InfoEntries; i++)
1205 {
1206 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
1207 if (0 == RtlCompareUnicodeString(&InfoFaceName, FaceName, TRUE))
1208 {
1209 return i;
1210 }
1211 }
1212
1213 return -1;
1214 }
1215
1216 static BOOLEAN FASTCALL
1217 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
1218 PFONTFAMILYINFO Info, DWORD InfoEntries)
1219 {
1220 UNICODE_STRING LogFontFaceName;
1221
1222 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
1223 if (0 != LogFontFaceName.Length
1224 && 0 != RtlCompareUnicodeString(&LogFontFaceName, FaceName, TRUE))
1225 {
1226 return FALSE;
1227 }
1228
1229 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
1230 }
1231
1232 static BOOLEAN FASTCALL
1233 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
1234 PFONTFAMILYINFO Info,
1235 DWORD *Count,
1236 DWORD Size,
1237 PLIST_ENTRY Head)
1238 {
1239 PLIST_ENTRY Entry;
1240 PFONT_ENTRY CurrentEntry;
1241 ANSI_STRING EntryFaceNameA;
1242 UNICODE_STRING EntryFaceNameW;
1243 FONTGDI *FontGDI;
1244
1245 Entry = Head->Flink;
1246 while (Entry != Head)
1247 {
1248 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1249
1250 FontGDI = CurrentEntry->Font;
1251 ASSERT(FontGDI);
1252
1253 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
1254 RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
1255 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
1256 {
1257 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
1258 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
1259 }
1260
1261 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
1262 {
1263 if (*Count < Size)
1264 {
1265 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
1266 }
1267 (*Count)++;
1268 }
1269 RtlFreeUnicodeString(&EntryFaceNameW);
1270 Entry = Entry->Flink;
1271 }
1272
1273 return TRUE;
1274 }
1275
1276 typedef struct FontFamilyInfoCallbackContext
1277 {
1278 LPLOGFONTW LogFont;
1279 PFONTFAMILYINFO Info;
1280 DWORD Count;
1281 DWORD Size;
1282 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
1283
1284 static NTSTATUS STDCALL
1285 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
1286 IN PVOID ValueData, IN ULONG ValueLength,
1287 IN PVOID Context, IN PVOID EntryContext)
1288 {
1289 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
1290 UNICODE_STRING RegistryName, RegistryValue;
1291 int Existing;
1292 PFONTGDI FontGDI;
1293
1294 if (REG_SZ != ValueType)
1295 {
1296 return STATUS_SUCCESS;
1297 }
1298 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
1299 RtlInitUnicodeString(&RegistryName, ValueName);
1300
1301 /* Do we need to include this font family? */
1302 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
1303 min(InfoContext->Count, InfoContext->Size)))
1304 {
1305 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
1306 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
1307 min(InfoContext->Count, InfoContext->Size));
1308 if (0 <= Existing)
1309 {
1310 /* We already have the information about the "real" font. Just copy it */
1311 if (InfoContext->Count < InfoContext->Size)
1312 {
1313 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
1314 wcsncpy(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
1315 RegistryName.Buffer, LF_FACESIZE);
1316 }
1317 InfoContext->Count++;
1318 return STATUS_SUCCESS;
1319 }
1320
1321 /* Try to find information about the "real" font */
1322 FontGDI = FindFaceNameInLists(&RegistryValue);
1323 if (NULL == FontGDI)
1324 {
1325 /* "Real" font not found, discard this registry entry */
1326 return STATUS_SUCCESS;
1327 }
1328
1329 /* Return info about the "real" font but with the name of the alias */
1330 if (InfoContext->Count < InfoContext->Size)
1331 {
1332 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
1333 RegistryName.Buffer, FontGDI);
1334 }
1335 InfoContext->Count++;
1336 return STATUS_SUCCESS;
1337 }
1338
1339 return STATUS_SUCCESS;
1340 }
1341
1342 static BOOLEAN FASTCALL
1343 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
1344 PFONTFAMILYINFO Info,
1345 DWORD *Count,
1346 DWORD Size)
1347 {
1348 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1349 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
1350 NTSTATUS Status;
1351
1352 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\SysFontSubstitutes
1353 The real work is done in the registry callback function */
1354 Context.LogFont = LogFont;
1355 Context.Info = Info;
1356 Context.Count = *Count;
1357 Context.Size = Size;
1358
1359 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
1360 QueryTable[0].Flags = 0;
1361 QueryTable[0].Name = NULL;
1362 QueryTable[0].EntryContext = NULL;
1363 QueryTable[0].DefaultType = REG_NONE;
1364 QueryTable[0].DefaultData = NULL;
1365 QueryTable[0].DefaultLength = 0;
1366
1367 QueryTable[1].QueryRoutine = NULL;
1368 QueryTable[1].Name = NULL;
1369
1370 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
1371 L"SysFontSubstitutes",
1372 QueryTable,
1373 &Context,
1374 NULL);
1375 if (NT_SUCCESS(Status))
1376 {
1377 *Count = Context.Count;
1378 }
1379
1380 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
1381 }
1382
1383 int STDCALL
1384 NtGdiGetFontFamilyInfo(HDC Dc,
1385 LPLOGFONTW UnsafeLogFont,
1386 PFONTFAMILYINFO UnsafeInfo,
1387 DWORD Size)
1388 {
1389 NTSTATUS Status;
1390 LOGFONTW LogFont;
1391 PFONTFAMILYINFO Info;
1392 DWORD Count;
1393 PW32PROCESS Win32Process;
1394
1395 /* Make a safe copy */
1396 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
1397 if (! NT_SUCCESS(Status))
1398 {
1399 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1400 return -1;
1401 }
1402
1403 /* Allocate space for a safe copy */
1404 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), TAG_GDITEXT);
1405 if (NULL == Info)
1406 {
1407 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1408 return -1;
1409 }
1410
1411 /* Enumerate font families in the global list */
1412 IntLockGlobalFonts;
1413 Count = 0;
1414 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
1415 {
1416 IntUnLockGlobalFonts;
1417 ExFreePool(Info);
1418 return -1;
1419 }
1420 IntUnLockGlobalFonts;
1421
1422 /* Enumerate font families in the process local list */
1423 Win32Process = PsGetWin32Process();
1424 IntLockProcessPrivateFonts(Win32Process);
1425 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
1426 &Win32Process->PrivateFontListHead))
1427 {
1428 IntUnLockProcessPrivateFonts(Win32Process);
1429 ExFreePool(Info);
1430 return -1;
1431 }
1432 IntUnLockProcessPrivateFonts(Win32Process);
1433
1434 /* Enumerate font families in the registry */
1435 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
1436 {
1437 ExFreePool(Info);
1438 return -1;
1439 }
1440
1441 /* Return data to caller */
1442 if (0 != Count)
1443 {
1444 Status = MmCopyToCaller(UnsafeInfo, Info,
1445 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
1446 if (! NT_SUCCESS(Status))
1447 {
1448 ExFreePool(Info);
1449 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1450 return -1;
1451 }
1452 }
1453
1454 ExFreePool(Info);
1455
1456 return Count;
1457 }
1458
1459 int
1460 STDCALL
1461 NtGdiEnumFonts(HDC hDC,
1462 LPCWSTR FaceName,
1463 FONTENUMPROCW FontFunc,
1464 LPARAM lParam)
1465 {
1466 UNIMPLEMENTED;
1467 return 0;
1468 }
1469
1470 BOOL STDCALL
1471 NtGdiExtTextOut(
1472 HDC hDC,
1473 INT XStart,
1474 INT YStart,
1475 UINT fuOptions,
1476 CONST RECT *lprc,
1477 LPCWSTR String,
1478 UINT Count,
1479 CONST INT *UnsafeDx)
1480 {
1481 /*
1482 * FIXME:
1483 * Call EngTextOut, which does the real work (calling DrvTextOut where
1484 * appropriate)
1485 */
1486
1487 DC *dc;
1488 SURFOBJ *SurfObj;
1489 BITMAPOBJ *BitmapObj;
1490 int error, glyph_index, n, i;
1491 FT_Face face;
1492 FT_GlyphSlot glyph;
1493 LONGLONG TextLeft, RealXStart;
1494 ULONG TextTop, pitch, previous, BackgroundLeft;
1495 FT_Bool use_kerning;
1496 RECTL DestRect, MaskRect, SpecifiedDestRect;
1497 POINTL SourcePoint, BrushOrigin;
1498 HBRUSH hBrushFg = NULL;
1499 PGDIBRUSHOBJ BrushFg = NULL;
1500 GDIBRUSHINST BrushFgInst;
1501 HBRUSH hBrushBg = NULL;
1502 PGDIBRUSHOBJ BrushBg = NULL;
1503 GDIBRUSHINST BrushBgInst;
1504 HBITMAP HSourceGlyph;
1505 SURFOBJ *SourceGlyphSurf;
1506 SIZEL bitSize;
1507 FT_CharMap found = 0, charmap;
1508 INT yoff;
1509 FONTOBJ *FontObj;
1510 PFONTGDI FontGDI;
1511 PTEXTOBJ TextObj = NULL;
1512 PPALGDI PalDestGDI;
1513 XLATEOBJ *XlateObj=NULL, *XlateObj2=NULL;
1514 ULONG Mode;
1515 FT_Render_Mode RenderMode;
1516 BOOLEAN Render;
1517 NTSTATUS Status;
1518 INT *Dx = NULL;
1519 POINT Start;
1520 BOOL DoBreak = FALSE;
1521
1522 // TODO: Write test-cases to exactly match real Windows in different
1523 // bad parameters (e.g. does Windows check the DC or the RECT first?).
1524 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
1525 {
1526 // At least one of the two flags were specified. Copy lprc. Once.
1527 Status = MmCopyFromCaller(&SpecifiedDestRect, lprc, sizeof(RECT));
1528 if (!NT_SUCCESS(Status))
1529 {
1530 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1531 return FALSE;
1532 }
1533 }
1534
1535 dc = DC_LockDc(hDC);
1536 if (!dc)
1537 {
1538 SetLastWin32Error(ERROR_INVALID_HANDLE);
1539 return FALSE;
1540 }
1541
1542 if (NULL != UnsafeDx && Count > 0)
1543 {
1544 Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
1545 if (NULL == Dx)
1546 {
1547 goto fail;
1548 }
1549 Status = MmCopyFromCaller(Dx, UnsafeDx, Count * sizeof(INT));
1550 if (! NT_SUCCESS(Status))
1551 {
1552 goto fail;
1553 }
1554 }
1555
1556 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
1557 if ( !BitmapObj )
1558 {
1559 goto fail;
1560 }
1561 SurfObj = &BitmapObj->SurfObj;
1562 ASSERT(SurfObj);
1563
1564 Start.x = XStart; Start.y = YStart;
1565 IntLPtoDP(dc, &Start, 1);
1566
1567 RealXStart = (Start.x + dc->w.DCOrgX) << 6;
1568 YStart = Start.y + dc->w.DCOrgY;
1569
1570 /* Create the brushes */
1571 PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
1572 if ( !PalDestGDI )
1573 Mode = PAL_RGB;
1574 else
1575 {
1576 Mode = PalDestGDI->Mode;
1577 PALETTE_UnlockPalette(dc->w.hPalette);
1578 }
1579 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
1580 if ( !XlateObj )
1581 {
1582 goto fail;
1583 }
1584 hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
1585 if ( !hBrushFg )
1586 {
1587 goto fail;
1588 }
1589 BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
1590 if ( !BrushFg )
1591 {
1592 goto fail;
1593 }
1594 IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);
1595 if ((fuOptions & ETO_OPAQUE) || dc->w.backgroundMode == OPAQUE)
1596 {
1597 hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor));
1598 if ( !hBrushBg )
1599 {
1600 goto fail;
1601 }
1602 BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
1603 if ( !BrushBg )
1604 {
1605 goto fail;
1606 }
1607 IntGdiInitBrushInstance(&BrushBgInst, BrushBg, NULL);
1608 }
1609 XlateObj2 = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, Mode, NULL, dc->w.hPalette);
1610 if ( !XlateObj2 )
1611 {
1612 goto fail;
1613 }
1614
1615 SourcePoint.x = 0;
1616 SourcePoint.y = 0;
1617 MaskRect.left = 0;
1618 MaskRect.top = 0;
1619 BrushOrigin.x = 0;
1620 BrushOrigin.y = 0;
1621
1622 if ((fuOptions & ETO_OPAQUE) && lprc)
1623 {
1624 DestRect.left = SpecifiedDestRect.left + dc->w.DCOrgX;
1625 DestRect.top = SpecifiedDestRect.top + dc->w.DCOrgY;
1626 DestRect.right = SpecifiedDestRect.right + dc->w.DCOrgX;
1627 DestRect.bottom = SpecifiedDestRect.bottom + dc->w.DCOrgY;
1628 IntEngBitBlt(
1629 BitmapObj,
1630 NULL,
1631 NULL,
1632 dc->CombinedClip,
1633 NULL,
1634 &DestRect,
1635 &SourcePoint,
1636 &SourcePoint,
1637 &BrushBgInst.BrushObject,
1638 &BrushOrigin,
1639 ROP3_TO_ROP4(PATCOPY));
1640 fuOptions &= ~ETO_OPAQUE;
1641 }
1642 else
1643 {
1644 if (dc->w.backgroundMode == OPAQUE)
1645 {
1646 fuOptions |= ETO_OPAQUE;
1647 }
1648 }
1649
1650 TextObj = TEXTOBJ_LockText(dc->w.hFont);
1651 if(TextObj == NULL)
1652 {
1653 goto fail;
1654 }
1655
1656 FontObj = TextObj->Font;
1657 ASSERT(FontObj);
1658 FontGDI = ObjToGDI(FontObj, FONT);
1659 ASSERT(FontGDI);
1660
1661 face = FontGDI->face;
1662 if (face->charmap == NULL)
1663 {
1664 DPRINT("WARNING: No charmap selected!\n");
1665 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
1666
1667 for (n = 0; n < face->num_charmaps; n++)
1668 {
1669 charmap = face->charmaps[n];
1670 DPRINT("found charmap encoding: %u\n", charmap->encoding);
1671 if (charmap->encoding != 0)
1672 {
1673 found = charmap;
1674 break;
1675 }
1676 }
1677 if (!found)
1678 {
1679 DPRINT1("WARNING: Could not find desired charmap!\n");
1680 }
1681 IntLockFreeType;
1682 error = FT_Set_Charmap(face, found);
1683 IntUnLockFreeType;
1684 if (error)
1685 {
1686 DPRINT1("WARNING: Could not set the charmap!\n");
1687 }
1688 }
1689
1690 Render = IntIsFontRenderingEnabled();
1691 if (Render)
1692 RenderMode = IntGetFontRenderMode(&TextObj->logfont);
1693 else
1694 RenderMode = FT_RENDER_MODE_MONO;
1695
1696 IntLockFreeType;
1697 error = FT_Set_Pixel_Sizes(
1698 face,
1699 TextObj->logfont.lfWidth,
1700 /* FIXME should set character height if neg */
1701 (TextObj->logfont.lfHeight < 0 ?
1702 - TextObj->logfont.lfHeight :
1703 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
1704 IntUnLockFreeType;
1705 if (error)
1706 {
1707 DPRINT1("Error in setting pixel sizes: %u\n", error);
1708 goto fail;
1709 }
1710
1711 /*
1712 * Process the vertical alignment and determine the yoff.
1713 */
1714
1715 if (dc->w.textAlign & TA_BASELINE)
1716 yoff = 0;
1717 else if (dc->w.textAlign & TA_BOTTOM)
1718 yoff = -face->size->metrics.descender >> 6;
1719 else /* TA_TOP */
1720 yoff = face->size->metrics.ascender >> 6;
1721
1722 use_kerning = FT_HAS_KERNING(face);
1723 previous = 0;
1724
1725 /*
1726 * Process the horizontal alignment and modify XStart accordingly.
1727 */
1728
1729 if (dc->w.textAlign & (TA_RIGHT | TA_CENTER))
1730 {
1731 ULONGLONG TextWidth = 0;
1732 LPCWSTR TempText = String;
1733 int Start;
1734
1735 /*
1736 * Calculate width of the text.
1737 */
1738
1739 if (NULL != Dx)
1740 {
1741 Start = Count < 2 ? 0 : Count - 2;
1742 TextWidth = Count < 2 ? 0 : (Dx[Count - 2] << 6);
1743 }
1744 else
1745 {
1746 Start = 0;
1747 }
1748 TempText = String + Start;
1749
1750 for (i = Start; i < Count; i++)
1751 {
1752 IntLockFreeType;
1753 glyph_index = FT_Get_Char_Index(face, *TempText);
1754 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1755 IntUnLockFreeType;
1756
1757 if (error)
1758 {
1759 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1760 }
1761
1762 glyph = face->glyph;
1763
1764 /* retrieve kerning distance */
1765 if (use_kerning && previous && glyph_index)
1766 {
1767 FT_Vector delta;
1768 IntLockFreeType;
1769 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1770 IntUnLockFreeType;
1771 TextWidth += delta.x;
1772 }
1773
1774 TextWidth += glyph->advance.x;
1775
1776 previous = glyph_index;
1777 TempText++;
1778 }
1779
1780 previous = 0;
1781
1782 if (dc->w.textAlign & TA_RIGHT)
1783 {
1784 RealXStart -= TextWidth;
1785 }
1786 else
1787 {
1788 RealXStart -= TextWidth / 2;
1789 }
1790 }
1791
1792 TextLeft = RealXStart;
1793 TextTop = YStart;
1794 BackgroundLeft = (RealXStart + 32) >> 6;
1795
1796 /*
1797 * The main rendering loop.
1798 */
1799
1800 for (i = 0; i < Count; i++)
1801 {
1802 IntLockFreeType;
1803 glyph_index = FT_Get_Char_Index(face, *String);
1804 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1805 IntUnLockFreeType;
1806
1807 if (error)
1808 {
1809 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1810 goto fail;
1811 }
1812
1813 glyph = face->glyph;
1814
1815 /* retrieve kerning distance and move pen position */
1816 if (use_kerning && previous && glyph_index && NULL == Dx)
1817 {
1818 FT_Vector delta;
1819 IntLockFreeType;
1820 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1821 IntUnLockFreeType;
1822 TextLeft += delta.x;
1823 }
1824
1825 if (glyph->format == ft_glyph_format_outline)
1826 {
1827 IntLockFreeType;
1828 error = FT_Render_Glyph(glyph, RenderMode);
1829 IntUnLockFreeType;
1830 if (error)
1831 {
1832 DPRINT1("WARNING: Failed to render glyph!\n");
1833 goto fail;
1834 }
1835 pitch = glyph->bitmap.pitch;
1836 } else {
1837 pitch = glyph->bitmap.width;
1838 }
1839
1840 if (fuOptions & ETO_OPAQUE)
1841 {
1842 DestRect.left = BackgroundLeft;
1843 DestRect.right = (TextLeft + glyph->advance.x + 32) >> 6;
1844 DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6);
1845 DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6);
1846 IntEngBitBlt(
1847 BitmapObj,
1848 NULL,
1849 NULL,
1850 dc->CombinedClip,
1851 NULL,
1852 &DestRect,
1853 &SourcePoint,
1854 &SourcePoint,
1855 &BrushBgInst.BrushObject,
1856 &BrushOrigin,
1857 ROP3_TO_ROP4(PATCOPY));
1858 BackgroundLeft = DestRect.right;
1859 }
1860
1861 DestRect.left = ((TextLeft + 32) >> 6) + glyph->bitmap_left;
1862 DestRect.right = DestRect.left + glyph->bitmap.width;
1863 DestRect.top = TextTop + yoff - glyph->bitmap_top;
1864 DestRect.bottom = DestRect.top + glyph->bitmap.rows;
1865
1866 bitSize.cx = glyph->bitmap.width;
1867 bitSize.cy = glyph->bitmap.rows;
1868 MaskRect.right = glyph->bitmap.width;
1869 MaskRect.bottom = glyph->bitmap.rows;
1870
1871 /*
1872 * We should create the bitmap out of the loop at the biggest possible
1873 * glyph size. Then use memset with 0 to clear it and sourcerect to
1874 * limit the work of the transbitblt.
1875 */
1876
1877 HSourceGlyph = EngCreateBitmap(bitSize, pitch, (glyph->bitmap.pixel_mode == ft_pixel_mode_grays) ? BMF_8BPP : BMF_1BPP, BMF_TOPDOWN, glyph->bitmap.buffer);
1878 if ( !HSourceGlyph )
1879 {
1880 DPRINT1("WARNING: EngLockSurface() failed!\n");
1881 goto fail;
1882 }
1883 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
1884 if ( !SourceGlyphSurf )
1885 {
1886 EngDeleteSurface((HSURF)HSourceGlyph);
1887 DPRINT1("WARNING: EngLockSurface() failed!\n");
1888 goto fail;
1889 }
1890
1891 /*
1892 * Use the font data as a mask to paint onto the DCs surface using a
1893 * brush.
1894 */
1895
1896 if (lprc &&
1897 (fuOptions & ETO_CLIPPED) &&
1898 DestRect.right >= SpecifiedDestRect.right + dc->w.DCOrgX)
1899 {
1900 // We do the check '>=' instead of '>' to possibly save an iteration
1901 // through this loop, since it's breaking after the drawing is done,
1902 // and x is always incremented.
1903 DestRect.right = SpecifiedDestRect.right + dc->w.DCOrgX;
1904 DoBreak = TRUE;
1905 }
1906
1907 IntEngMaskBlt(
1908 SurfObj,
1909 SourceGlyphSurf,
1910 dc->CombinedClip,
1911 XlateObj,
1912 XlateObj2,
1913 &DestRect,
1914 &SourcePoint,
1915 (PPOINTL)&MaskRect,
1916 &BrushFgInst.BrushObject,
1917 &BrushOrigin);
1918
1919 EngUnlockSurface(SourceGlyphSurf);
1920 EngDeleteSurface((HSURF)HSourceGlyph);
1921
1922 if (DoBreak)
1923 {
1924 break;
1925 }
1926
1927 if (NULL == Dx)
1928 {
1929 TextLeft += glyph->advance.x;
1930 }
1931 else
1932 {
1933 TextLeft += Dx[i] << 6;
1934 }
1935 previous = glyph_index;
1936
1937 String++;
1938 }
1939
1940 EngDeleteXlate(XlateObj);
1941 EngDeleteXlate(XlateObj2);
1942 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
1943 if(TextObj != NULL)
1944 TEXTOBJ_UnlockText(dc->w.hFont);
1945 if (hBrushBg != NULL)
1946 {
1947 BRUSHOBJ_UnlockBrush(hBrushBg);
1948 NtGdiDeleteObject(hBrushBg);
1949 }
1950 BRUSHOBJ_UnlockBrush(hBrushFg);
1951 NtGdiDeleteObject(hBrushFg);
1952 if (NULL != Dx)
1953 {
1954 ExFreePool(Dx);
1955 }
1956 DC_UnlockDc( hDC );
1957
1958 return TRUE;
1959
1960 fail:
1961 if ( XlateObj2 != NULL )
1962 EngDeleteXlate(XlateObj2);
1963 if ( XlateObj != NULL )
1964 EngDeleteXlate(XlateObj);
1965 if(TextObj != NULL)
1966 TEXTOBJ_UnlockText(dc->w.hFont);
1967 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
1968 if (hBrushBg != NULL)
1969 {
1970 BRUSHOBJ_UnlockBrush(hBrushBg);
1971 NtGdiDeleteObject(hBrushBg);
1972 }
1973 if (hBrushFg != NULL)
1974 {
1975 BRUSHOBJ_UnlockBrush(hBrushFg);
1976 NtGdiDeleteObject(hBrushFg);
1977 }
1978 if (NULL != Dx)
1979 {
1980 ExFreePool(Dx);
1981 }
1982 DC_UnlockDc(hDC);
1983
1984 return FALSE;
1985 }
1986
1987 BOOL
1988 STDCALL
1989 NtGdiGetAspectRatioFilterEx(HDC hDC,
1990 LPSIZE AspectRatio)
1991 {
1992 UNIMPLEMENTED;
1993 return FALSE;
1994 }
1995
1996 BOOL
1997 STDCALL
1998 NtGdiGetCharABCWidths(HDC hDC,
1999 UINT FirstChar,
2000 UINT LastChar,
2001 LPABC abc)
2002 {
2003 DPRINT1("NtGdiGetCharABCWidths Is unimplemented, keep going anyway\n");
2004 return 1;
2005 }
2006
2007 BOOL
2008 STDCALL
2009 NtGdiGetCharABCWidthsFloat(HDC hDC,
2010 UINT FirstChar,
2011 UINT LastChar,
2012 LPABCFLOAT abcF)
2013 {
2014 UNIMPLEMENTED;
2015 return FALSE;
2016 }
2017
2018 DWORD
2019 STDCALL
2020 NtGdiGetCharacterPlacement(HDC hDC,
2021 LPCWSTR String,
2022 int Count,
2023 int MaxExtent,
2024 LPGCP_RESULTSW Results,
2025 DWORD Flags)
2026 {
2027 UNIMPLEMENTED;
2028 return 0;
2029 }
2030
2031 BOOL
2032 STDCALL
2033 NtGdiGetCharWidth32(HDC hDC,
2034 UINT FirstChar,
2035 UINT LastChar,
2036 LPINT Buffer)
2037 {
2038 LPINT SafeBuffer;
2039 PDC dc;
2040 PTEXTOBJ TextObj;
2041 PFONTGDI FontGDI;
2042 FT_Face face;
2043 FT_CharMap charmap, found = NULL;
2044 UINT i, glyph_index, BufferSize;
2045 HFONT hFont = 0;
2046
2047 if (LastChar < FirstChar)
2048 {
2049 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2050 return FALSE;
2051 }
2052
2053 BufferSize = (LastChar - FirstChar + 1) * sizeof(INT);
2054 SafeBuffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
2055 if (SafeBuffer == NULL)
2056 {
2057 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2058 return FALSE;
2059 }
2060
2061 dc = DC_LockDc(hDC);
2062 if (dc == NULL)
2063 {
2064 ExFreePool(SafeBuffer);
2065 SetLastWin32Error(ERROR_INVALID_HANDLE);
2066 return FALSE;
2067 }
2068 hFont = dc->w.hFont;
2069 TextObj = TEXTOBJ_LockText(hFont);
2070 DC_UnlockDc(hDC);
2071
2072 if (TextObj == NULL)
2073 {
2074 ExFreePool(SafeBuffer);
2075 SetLastWin32Error(ERROR_INVALID_HANDLE);
2076 return FALSE;
2077 }
2078
2079 FontGDI = ObjToGDI(TextObj->Font, FONT);
2080
2081 face = FontGDI->face;
2082 if (face->charmap == NULL)
2083 {
2084 for (i = 0; i < face->num_charmaps; i++)
2085 {
2086 charmap = face->charmaps[i];
2087 if (charmap->encoding != 0)
2088 {
2089 found = charmap;
2090 break;
2091 }
2092 }
2093
2094 if (!found)
2095 {
2096 DPRINT1("WARNING: Could not find desired charmap!\n");
2097 ExFreePool(SafeBuffer);
2098 SetLastWin32Error(ERROR_INVALID_HANDLE);
2099 return FALSE;
2100 }
2101
2102 IntLockFreeType;
2103 FT_Set_Charmap(face, found);
2104 IntUnLockFreeType;
2105 }
2106
2107 IntLockFreeType;
2108 FT_Set_Pixel_Sizes(face,
2109 TextObj->logfont.lfWidth,
2110 /* FIXME should set character height if neg */
2111 (TextObj->logfont.lfHeight < 0 ?
2112 - TextObj->logfont.lfHeight :
2113 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
2114
2115 for (i = FirstChar; i <= LastChar; i++)
2116 {
2117 glyph_index = FT_Get_Char_Index(face, i);
2118 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2119 SafeBuffer[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
2120 }
2121 IntUnLockFreeType;
2122 TEXTOBJ_UnlockText(hFont);
2123 MmCopyToCaller(Buffer, SafeBuffer, BufferSize);
2124 ExFreePool(SafeBuffer);
2125 return TRUE;
2126 }
2127
2128 BOOL
2129 STDCALL
2130 NtGdiGetCharWidthFloat(HDC hDC,
2131 UINT FirstChar,
2132 UINT LastChar,
2133 PFLOAT Buffer)
2134 {
2135 UNIMPLEMENTED;
2136 return FALSE;
2137 }
2138
2139 DWORD
2140 STDCALL
2141 NtGdiGetFontLanguageInfo(HDC hDC)
2142 {
2143 UNIMPLEMENTED;
2144 return 0;
2145 }
2146
2147 DWORD
2148 STDCALL
2149 NtGdiGetGlyphOutline(HDC hDC,
2150 UINT Char,
2151 UINT Format,
2152 LPGLYPHMETRICS gm,
2153 DWORD Bufsize,
2154 LPVOID Buffer,
2155 CONST LPMAT2 mat2)
2156 {
2157 UNIMPLEMENTED;
2158 return 0;
2159 }
2160
2161 DWORD
2162 STDCALL
2163 NtGdiGetKerningPairs(HDC hDC,
2164 DWORD NumPairs,
2165 LPKERNINGPAIR krnpair)
2166 {
2167 UNIMPLEMENTED;
2168 return 0;
2169 }
2170
2171 UINT
2172 STDCALL
2173 NtGdiGetOutlineTextMetrics(HDC hDC,
2174 UINT Data,
2175 LPOUTLINETEXTMETRICW otm)
2176 {
2177 UNIMPLEMENTED;
2178 return 0;
2179 }
2180
2181 BOOL
2182 STDCALL
2183 NtGdiGetRasterizerCaps(LPRASTERIZER_STATUS rs,
2184 UINT Size)
2185 {
2186 UNIMPLEMENTED;
2187 return FALSE;
2188 }
2189
2190 UINT
2191 STDCALL
2192 NtGdiGetTextCharset(HDC hDC)
2193 {
2194 UNIMPLEMENTED;
2195 return 0;
2196 }
2197
2198 UINT
2199 STDCALL
2200 NtGdiGetTextCharsetInfo(HDC hDC,
2201 LPFONTSIGNATURE Sig,
2202 DWORD Flags)
2203 {
2204 UNIMPLEMENTED;
2205 return 0;
2206 }
2207
2208 static BOOL
2209 FASTCALL
2210 TextIntGetTextExtentPoint(PDC dc,
2211 PTEXTOBJ TextObj,
2212 LPCWSTR String,
2213 int Count,
2214 int MaxExtent,
2215 LPINT Fit,
2216 LPINT Dx,
2217 LPSIZE Size)
2218 {
2219 PFONTGDI FontGDI;
2220 FT_Face face;
2221 FT_GlyphSlot glyph;
2222 INT error, n, glyph_index, i, previous;
2223 ULONGLONG TotalWidth = 0;
2224 FT_CharMap charmap, found = NULL;
2225 BOOL use_kerning;
2226
2227 FontGDI = ObjToGDI(TextObj->Font, FONT);
2228
2229 face = FontGDI->face;
2230 if (NULL != Fit)
2231 {
2232 *Fit = 0;
2233 }
2234
2235 if (face->charmap == NULL)
2236 {
2237 DPRINT("WARNING: No charmap selected!\n");
2238 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2239
2240 for (n = 0; n < face->num_charmaps; n++)
2241 {
2242 charmap = face->charmaps[n];
2243 DPRINT("found charmap encoding: %u\n", charmap->encoding);
2244 if (charmap->encoding != 0)
2245 {
2246 found = charmap;
2247 break;
2248 }
2249 }
2250
2251 if (! found)
2252 {
2253 DPRINT1("WARNING: Could not find desired charmap!\n");
2254 }
2255
2256 IntLockFreeType;
2257 error = FT_Set_Charmap(face, found);
2258 IntUnLockFreeType;
2259 if (error)
2260 {
2261 DPRINT1("WARNING: Could not set the charmap!\n");
2262 }
2263 }
2264
2265 IntLockFreeType;
2266 error = FT_Set_Pixel_Sizes(face,
2267 TextObj->logfont.lfWidth,
2268 /* FIXME should set character height if neg */
2269 (TextObj->logfont.lfHeight < 0 ?
2270 - TextObj->logfont.lfHeight :
2271 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
2272 IntUnLockFreeType;
2273 if (error)
2274 {
2275 DPRINT1("Error in setting pixel sizes: %u\n", error);
2276 }
2277
2278 use_kerning = FT_HAS_KERNING(face);
2279 previous = 0;
2280
2281 for (i = 0; i < Count; i++)
2282 {
2283 IntLockFreeType;
2284 glyph_index = FT_Get_Char_Index(face, *String);
2285 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2286 IntUnLockFreeType;
2287 if (error)
2288 {
2289 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
2290 }
2291 glyph = face->glyph;
2292
2293 /* retrieve kerning distance */
2294 if (use_kerning && previous && glyph_index)
2295 {
2296 FT_Vector delta;
2297 IntLockFreeType;
2298 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
2299 IntUnLockFreeType;
2300 TotalWidth += delta.x;
2301 }
2302
2303 TotalWidth += glyph->advance.x;
2304
2305 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
2306 {
2307 *Fit = i + 1;
2308 }
2309 if (NULL != Dx)
2310 {
2311 Dx[i] = (TotalWidth + 32) >> 6;
2312 }
2313
2314 previous = glyph_index;
2315 String++;
2316 }
2317
2318 Size->cx = (TotalWidth + 32) >> 6;
2319 Size->cy = (TextObj->logfont.lfHeight < 0 ? - TextObj->logfont.lfHeight : TextObj->logfont.lfHeight);
2320 Size->cy = EngMulDiv(Size->cy, IntGdiGetDeviceCaps(dc, LOGPIXELSY), 72);
2321
2322 return TRUE;
2323 }
2324
2325 BOOL
2326 STDCALL
2327 NtGdiGetTextExtentExPoint(HDC hDC,
2328 LPCWSTR UnsafeString,
2329 int Count,
2330 int MaxExtent,
2331 LPINT UnsafeFit,
2332 LPINT UnsafeDx,
2333 LPSIZE UnsafeSize)
2334 {
2335 PDC dc;
2336 LPWSTR String;
2337 SIZE Size;
2338 NTSTATUS Status;
2339 BOOLEAN Result;
2340 INT Fit;
2341 LPINT Dx;
2342 PTEXTOBJ TextObj;
2343
2344 if (Count < 0)
2345 {
2346 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2347 return FALSE;
2348 }
2349 if (0 == Count)
2350 {
2351 Size.cx = 0;
2352 Size.cy = 0;
2353 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
2354 if (! NT_SUCCESS(Status))
2355 {
2356 SetLastNtError(Status);
2357 return FALSE;
2358 }
2359 return TRUE;
2360 }
2361
2362 String = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), TAG_GDITEXT);
2363 if (NULL == String)
2364 {
2365 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2366 return FALSE;
2367 }
2368
2369 if (NULL != UnsafeDx)
2370 {
2371 Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
2372 if (NULL == Dx)
2373 {
2374 ExFreePool(String);
2375 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2376 return FALSE;
2377 }
2378 }
2379 else
2380 {
2381 Dx = NULL;
2382 }
2383
2384 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
2385 if (! NT_SUCCESS(Status))
2386 {
2387 if (NULL != Dx)
2388 {
2389 ExFreePool(Dx);
2390 }
2391 ExFreePool(String);
2392 SetLastNtError(Status);
2393 return FALSE;
2394 }
2395
2396 dc = DC_LockDc(hDC);
2397 if (NULL == dc)
2398 {
2399 if (NULL != Dx)
2400 {
2401 ExFreePool(Dx);
2402 }
2403 ExFreePool(String);
2404 SetLastWin32Error(ERROR_INVALID_HANDLE);
2405 return FALSE;
2406 }
2407 TextObj = TEXTOBJ_LockText(dc->w.hFont);
2408 if ( TextObj )
2409 {
2410 Result = TextIntGetTextExtentPoint(dc, TextObj, String, Count, MaxExtent,
2411 NULL == UnsafeFit ? NULL : &Fit, Dx, &Size);
2412 }
2413 else
2414 Result = FALSE;
2415 TEXTOBJ_UnlockText(dc->w.hFont);
2416 DC_UnlockDc(hDC);
2417
2418 ExFreePool(String);
2419 if (! Result)
2420 {
2421 if (NULL != Dx)
2422 {
2423 ExFreePool(Dx);
2424 }
2425 return FALSE;
2426 }
2427
2428 if (NULL != UnsafeFit)
2429 {
2430 Status = MmCopyToCaller(UnsafeFit, &Fit, sizeof(INT));
2431 if (! NT_SUCCESS(Status))
2432 {
2433 if (NULL != Dx)
2434 {
2435 ExFreePool(Dx);
2436 }
2437 SetLastNtError(Status);
2438 return FALSE;
2439 }
2440 }
2441
2442 if (NULL != UnsafeDx)
2443 {
2444 Status = MmCopyToCaller(UnsafeDx, Dx, Count * sizeof(INT));
2445 if (! NT_SUCCESS(Status))
2446 {
2447 if (NULL != Dx)
2448 {
2449 ExFreePool(Dx);
2450 }
2451 SetLastNtError(Status);
2452 return FALSE;
2453 }
2454 }
2455 if (NULL != Dx)
2456 {
2457 ExFreePool(Dx);
2458 }
2459
2460 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
2461 if (! NT_SUCCESS(Status))
2462 {
2463 SetLastNtError(Status);
2464 return FALSE;
2465 }
2466
2467 return TRUE;
2468 }
2469
2470 BOOL
2471 STDCALL
2472 NtGdiGetTextExtentPoint(HDC hDC,
2473 LPCWSTR String,
2474 int Count,
2475 LPSIZE Size)
2476 {
2477 return NtGdiGetTextExtentExPoint(hDC, String, Count, 0, NULL, NULL, Size);
2478 }
2479
2480 BOOL
2481 STDCALL
2482 NtGdiGetTextExtentPoint32(HDC hDC,
2483 LPCWSTR UnsafeString,
2484 int Count,
2485 LPSIZE UnsafeSize)
2486 {
2487 PDC dc;
2488 LPWSTR String;
2489 SIZE Size;
2490 NTSTATUS Status;
2491 BOOLEAN Result;
2492 PTEXTOBJ TextObj;
2493
2494 if (Count < 0)
2495 {
2496 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2497 return FALSE;
2498 }
2499 if (0 == Count)
2500 {
2501 Size.cx = 0;
2502 Size.cy = 0;
2503 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
2504 if (! NT_SUCCESS(Status))
2505 {
2506 SetLastNtError(Status);
2507 return FALSE;
2508 }
2509 return TRUE;
2510 }
2511
2512 String = ExAllocatePool(PagedPool, Count * sizeof(WCHAR));
2513 if (NULL == String)
2514 {
2515 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2516 return FALSE;
2517 }
2518
2519 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
2520 if (! NT_SUCCESS(Status))
2521 {
2522 ExFreePool(String);
2523 SetLastNtError(Status);
2524 return FALSE;
2525 }
2526
2527 dc = DC_LockDc(hDC);
2528 if (NULL == dc)
2529 {
2530 ExFreePool(String);
2531 SetLastWin32Error(ERROR_INVALID_HANDLE);
2532 return FALSE;
2533 }
2534 TextObj = TEXTOBJ_LockText(dc->w.hFont);
2535 if ( TextObj != NULL )
2536 {
2537 Result = TextIntGetTextExtentPoint (
2538 dc, TextObj, String, Count, 0, NULL, NULL, &Size);
2539 TEXTOBJ_UnlockText(dc->w.hFont);
2540 }
2541 else
2542 Result = FALSE;
2543 DC_UnlockDc(hDC);
2544
2545 ExFreePool(String);
2546 if (! Result)
2547 {
2548 return FALSE;
2549 }
2550
2551 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
2552 if (! NT_SUCCESS(Status))
2553 {
2554 SetLastNtError(Status);
2555 return FALSE;
2556 }
2557
2558 return TRUE;
2559 }
2560
2561 INT STDCALL
2562 NtGdiGetTextFace(HDC hDC, INT Count, LPWSTR FaceName)
2563 {
2564 PDC Dc;
2565 PTEXTOBJ TextObj;
2566 NTSTATUS Status;
2567
2568 Dc = DC_LockDc(hDC);
2569 if (Dc == NULL)
2570 {
2571 SetLastWin32Error(ERROR_INVALID_HANDLE);
2572 return FALSE;
2573 }
2574 TextObj = TEXTOBJ_LockText(Dc->w.hFont);
2575 DC_UnlockDc(hDC);
2576
2577 Count = min(Count, wcslen(TextObj->logfont.lfFaceName));
2578 Status = MmCopyToCaller(FaceName, TextObj->logfont.lfFaceName, Count * sizeof(WCHAR));
2579 if (!NT_SUCCESS(Status))
2580 {
2581 SetLastNtError(Status);
2582 return 0;
2583 }
2584
2585 return Count;
2586 }
2587
2588 BOOL
2589 STDCALL
2590 NtGdiGetTextMetrics(HDC hDC,
2591 LPTEXTMETRICW tm)
2592 {
2593 PDC dc;
2594 PTEXTOBJ TextObj;
2595 PFONTGDI FontGDI;
2596 NTSTATUS Status = STATUS_SUCCESS;
2597 TEXTMETRICW SafeTm;
2598 FT_Face Face;
2599 TT_OS2 *pOS2;
2600 TT_HoriHeader *pHori;
2601 ULONG Error;
2602
2603 if (NULL == tm)
2604 {
2605 SetLastWin32Error(STATUS_INVALID_PARAMETER);
2606 return FALSE;
2607 }
2608
2609 if(!(dc = DC_LockDc(hDC)))
2610 {
2611 SetLastWin32Error(ERROR_INVALID_HANDLE);
2612 return FALSE;
2613 }
2614
2615 TextObj = TEXTOBJ_LockText(dc->w.hFont);
2616 if (NULL != TextObj)
2617 {
2618 FontGDI = ObjToGDI(TextObj->Font, FONT);
2619
2620 Face = FontGDI->face;
2621 IntLockFreeType;
2622 Error = FT_Set_Pixel_Sizes(Face,
2623 TextObj->logfont.lfWidth,
2624 /* FIXME should set character height if neg */
2625 (TextObj->logfont.lfHeight < 0 ?
2626 - TextObj->logfont.lfHeight :
2627 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
2628 IntUnLockFreeType;
2629 if (0 != Error)
2630 {
2631 DPRINT1("Error in setting pixel sizes: %u\n", Error);
2632 Status = STATUS_UNSUCCESSFUL;
2633 }
2634 else
2635 {
2636 memcpy(&SafeTm, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
2637
2638 Status = STATUS_SUCCESS;
2639 IntLockFreeType;
2640 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
2641 if (NULL == pOS2)
2642 {
2643 DPRINT1("Can't find OS/2 table - not TT font?\n");
2644 Status = STATUS_INTERNAL_ERROR;
2645 }
2646
2647 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
2648 if (NULL == pHori)
2649 {
2650 DPRINT1("Can't find HHEA table - not TT font?\n");
2651 Status = STATUS_INTERNAL_ERROR;
2652 }
2653
2654 IntUnLockFreeType;
2655
2656 if (NT_SUCCESS(Status))
2657 {
2658 FillTM(&SafeTm, FontGDI->face, pOS2, pHori);
2659 Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
2660 }
2661 }
2662 TEXTOBJ_UnlockText(dc->w.hFont);
2663 }
2664 else
2665 {
2666 Status = STATUS_INVALID_HANDLE;
2667 }
2668 DC_UnlockDc(hDC);
2669
2670 if(!NT_SUCCESS(Status))
2671 {
2672 SetLastNtError(Status);
2673 return FALSE;
2674 }
2675
2676 return TRUE;
2677 }
2678
2679 BOOL
2680 STDCALL
2681 NtGdiPolyTextOut(HDC hDC,
2682 CONST LPPOLYTEXTW txt,
2683 int Count)
2684 {
2685 UNIMPLEMENTED;
2686 return FALSE;
2687 }
2688
2689 BOOL
2690 STDCALL
2691 NtGdiRemoveFontResource(LPCWSTR FileName)
2692 {
2693 DPRINT1("NtGdiRemoveFontResource is UNIMPLEMENTED\n");
2694 return FALSE;
2695 }
2696
2697 DWORD
2698 STDCALL
2699 NtGdiSetMapperFlags(HDC hDC,
2700 DWORD Flag)
2701 {
2702 UNIMPLEMENTED;
2703 return 0;
2704 }
2705
2706 UINT
2707 STDCALL
2708 NtGdiSetTextAlign(HDC hDC,
2709 UINT Mode)
2710 {
2711 UINT prevAlign;
2712 DC *dc;
2713
2714 dc = DC_LockDc(hDC);
2715 if (!dc)
2716 {
2717 SetLastWin32Error(ERROR_INVALID_HANDLE);
2718 return GDI_ERROR;
2719 }
2720 prevAlign = dc->w.textAlign;
2721 dc->w.textAlign = Mode;
2722 DC_UnlockDc( hDC );
2723 return prevAlign;
2724 }
2725
2726 COLORREF
2727 STDCALL
2728 NtGdiSetTextColor(HDC hDC,
2729 COLORREF color)
2730 {
2731 COLORREF oldColor;
2732 PDC dc = DC_LockDc(hDC);
2733 HBRUSH hBrush;
2734
2735 if (!dc)
2736 {
2737 SetLastWin32Error(ERROR_INVALID_HANDLE);
2738 return CLR_INVALID;
2739 }
2740
2741 oldColor = dc->w.textColor;
2742 dc->w.textColor = color;
2743 hBrush = dc->w.hBrush;
2744 DC_UnlockDc( hDC );
2745 NtGdiSelectObject(hDC, hBrush);
2746 return oldColor;
2747 }
2748
2749 BOOL
2750 STDCALL
2751 NtGdiSetTextJustification(HDC hDC,
2752 int BreakExtra,
2753 int BreakCount)
2754 {
2755 UNIMPLEMENTED;
2756 return FALSE;
2757 }
2758
2759 BOOL STDCALL
2760 NtGdiTextOut(
2761 HDC hDC,
2762 INT XStart,
2763 INT YStart,
2764 LPCWSTR String,
2765 INT Count)
2766 {
2767 return NtGdiExtTextOut(hDC, XStart, YStart, 0, NULL, String, Count, NULL);
2768 }
2769
2770 DWORD STDCALL
2771 NtGdiGetFontData(
2772 HDC hDC,
2773 DWORD Table,
2774 DWORD Offset,
2775 LPVOID Buffer,
2776 DWORD Size)
2777 {
2778 PDC Dc;
2779 HFONT hFont;
2780 PTEXTOBJ TextObj;
2781 PFONTGDI FontGdi;
2782 DWORD Result = GDI_ERROR;
2783
2784 Dc = DC_LockDc(hDC);
2785 if (Dc == NULL)
2786 {
2787 SetLastWin32Error(ERROR_INVALID_HANDLE);
2788 return GDI_ERROR;
2789 }
2790 hFont = Dc->w.hFont;
2791 TextObj = TEXTOBJ_LockText(hFont);
2792 DC_UnlockDc(hDC);
2793
2794 if (TextObj == NULL)
2795 {
2796 SetLastWin32Error(ERROR_INVALID_HANDLE);
2797 return GDI_ERROR;
2798 }
2799
2800 FontGdi = ObjToGDI(TextObj->Font, FONT);
2801
2802 IntLockFreeType;
2803
2804 if (FT_IS_SFNT(FontGdi->face))
2805 {
2806 if (Table)
2807 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
2808 (Table << 8 & 0xFF0000);
2809
2810 if (Buffer == NULL)
2811 Size = 0;
2812
2813 if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
2814 Result = Size;
2815 }
2816
2817 IntUnLockFreeType;
2818
2819 TEXTOBJ_UnlockText(hFont);
2820
2821 return Result;
2822 }
2823
2824 static UINT FASTCALL
2825 GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
2826 {
2827 ANSI_STRING EntryFaceNameA;
2828 UNICODE_STRING EntryFaceNameW;
2829 unsigned Size;
2830 OUTLINETEXTMETRICW *Otm;
2831 LONG WeightDiff;
2832 NTSTATUS Status;
2833 UINT Score = 1;
2834
2835 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
2836 Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2837 if (NT_SUCCESS(Status))
2838 {
2839 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2840 {
2841 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2842 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2843 }
2844 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
2845 {
2846 Score += 49;
2847 }
2848 RtlFreeUnicodeString(&EntryFaceNameW);
2849 }
2850
2851 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2852 Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
2853 if (NULL == Otm)
2854 {
2855 return Score;
2856 }
2857 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2858
2859 if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
2860 (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
2861 {
2862 Score += 25;
2863 }
2864 if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
2865 {
2866 WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
2867 }
2868 else
2869 {
2870 WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
2871 }
2872 Score += (1000 - WeightDiff) / (1000 / 25);
2873
2874 ExFreePool(Otm);
2875
2876 return Score;
2877 }
2878
2879 static inline VOID
2880 FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
2881 PUNICODE_STRING FaceName, PLIST_ENTRY Head)
2882 {
2883 PLIST_ENTRY Entry;
2884 PFONT_ENTRY CurrentEntry;
2885 FONTGDI *FontGDI;
2886 UINT Score;
2887
2888 Entry = Head->Flink;
2889 while (Entry != Head)
2890 {
2891 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2892
2893 FontGDI = CurrentEntry->Font;
2894 ASSERT(FontGDI);
2895
2896 Score = GetFontScore(LogFont, FaceName, FontGDI);
2897 if (*MatchScore == 0 || *MatchScore < Score)
2898 {
2899 *FontObj = GDIToObj(FontGDI, FONT);
2900 *MatchScore = Score;
2901 }
2902 Entry = Entry->Flink;
2903 }
2904 }
2905
2906 static inline BOOLEAN
2907 SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
2908 LPCWSTR Key)
2909 {
2910 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
2911 NTSTATUS Status;
2912 UNICODE_STRING Value;
2913
2914 RtlInitUnicodeString(&Value, NULL);
2915
2916 QueryTable[0].QueryRoutine = NULL;
2917 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
2918 RTL_QUERY_REGISTRY_REQUIRED;
2919 QueryTable[0].Name = FaceName->Buffer;
2920 QueryTable[0].EntryContext = &Value;
2921 QueryTable[0].DefaultType = REG_NONE;
2922 QueryTable[0].DefaultData = NULL;
2923 QueryTable[0].DefaultLength = 0;
2924
2925 QueryTable[1].QueryRoutine = NULL;
2926 QueryTable[1].Name = NULL;
2927
2928 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2929 Key,
2930 QueryTable,
2931 NULL,
2932 NULL);
2933 if (NT_SUCCESS(Status))
2934 {
2935 RtlFreeUnicodeString(FaceName);
2936 *FaceName = Value;
2937 }
2938
2939 return NT_SUCCESS(Status);
2940 }
2941
2942 static inline void
2943 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
2944 {
2945 if (10 < Level) /* Enough is enough */
2946 {
2947 return;
2948 }
2949
2950 if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
2951 SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
2952 {
2953 SubstituteFontFamily(FaceName, Level + 1);
2954 }
2955 }
2956
2957 NTSTATUS FASTCALL
2958 TextIntRealizeFont(HFONT FontHandle)
2959 {
2960 NTSTATUS Status = STATUS_SUCCESS;
2961 PTEXTOBJ TextObj;
2962 UNICODE_STRING FaceName;
2963 PW32PROCESS Win32Process;
2964 UINT MatchScore;
2965
2966 TextObj = TEXTOBJ_LockText(FontHandle);
2967 if (NULL == TextObj)
2968 {
2969 return STATUS_INVALID_HANDLE;
2970 }
2971
2972 if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.lfFaceName))
2973 {
2974 TEXTOBJ_UnlockText(FontHandle);
2975 return STATUS_NO_MEMORY;
2976 }
2977 SubstituteFontFamily(&FaceName, 0);
2978 MatchScore = 0;
2979 TextObj->Font = NULL;
2980
2981 /* First search private fonts */
2982 Win32Process = PsGetWin32Process();
2983 IntLockProcessPrivateFonts(Win32Process);
2984 FindBestFontFromList(&TextObj->Font, &MatchScore,
2985 &TextObj->logfont, &FaceName,
2986 &Win32Process->PrivateFontListHead);
2987 IntUnLockProcessPrivateFonts(Win32Process);
2988
2989 /* Search system fonts */
2990 IntLockGlobalFonts;
2991 FindBestFontFromList(&TextObj->Font, &MatchScore,
2992 &TextObj->logfont, &FaceName,
2993 &FontListHead);
2994 IntUnLockGlobalFonts;
2995
2996 if (NULL == TextObj->Font)
2997 {
2998 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
2999 TextObj->logfont.lfFaceName);
3000 Status = STATUS_NOT_FOUND;
3001 }
3002 else
3003 {
3004 Status = STATUS_SUCCESS;
3005 }
3006
3007 RtlFreeUnicodeString(&FaceName);
3008 TEXTOBJ_UnlockText(FontHandle);
3009
3010 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
3011
3012 return Status;
3013 }
3014
3015 INT FASTCALL
3016 FontGetObject(PTEXTOBJ Font, INT Count, PVOID Buffer)
3017 {
3018 if (Count < sizeof(LOGFONTW))
3019 {
3020 SetLastWin32Error(ERROR_BUFFER_OVERFLOW);
3021 return 0;
3022 }
3023
3024 RtlCopyMemory(Buffer, &Font->logfont, sizeof(LOGFONTW));
3025
3026 return sizeof(LOGFONTW);
3027 }
3028
3029 /* EOF */