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