Allow NtGdiCreateScaleableFontResource to keep going.
[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.112 2004/10/07 05:26:54 sedwards 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 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 HFONT NewFont;
251 FONTOBJ *FontObj;
252 PFONTGDI FontGDI;
253 NTSTATUS Status;
254 HANDLE FileHandle;
255 OBJECT_ATTRIBUTES ObjectAttributes;
256 FILE_STANDARD_INFORMATION FileStdInfo;
257 PVOID Buffer;
258 IO_STATUS_BLOCK Iosb;
259 INT Error;
260 FT_Face Face;
261 ANSI_STRING AnsiFaceName;
262 PFONT_ENTRY Entry;
263
264 /* Create handle for the font */
265
266 NewFont = (HFONT)CreateGDIHandle(
267 sizeof(FONTGDI),
268 sizeof(FONTOBJ),
269 (PVOID*)&FontGDI,
270 (PVOID*)&FontObj);
271
272 if (NewFont == 0)
273 {
274 DPRINT("Could not allocate a new GDI font object\n");
275 return 0;
276 }
277
278 /* Open the font file */
279
280 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
281 Status = ZwOpenFile(
282 &FileHandle,
283 GENERIC_READ | SYNCHRONIZE,
284 &ObjectAttributes,
285 &Iosb,
286 0,
287 FILE_SYNCHRONOUS_IO_NONALERT);
288
289 if (!NT_SUCCESS(Status))
290 {
291 DPRINT("Could not font file: %wZ\n", FileName);
292 NtGdiDeleteObject(NewFont);
293 return 0;
294 }
295
296 /* Get the size of the file */
297
298 Status = NtQueryInformationFile(
299 FileHandle,
300 &Iosb,
301 &FileStdInfo,
302 sizeof(FileStdInfo),
303 FileStandardInformation);
304
305 if (!NT_SUCCESS(Status))
306 {
307 DPRINT("Could not get file size\n");
308 NtGdiDeleteObject(NewFont);
309 ZwClose(FileHandle);
310 return 0;
311 }
312
313 /* Allocate pageable memory for the font */
314
315 Buffer = ExAllocatePoolWithTag(
316 PagedPool,
317 FileStdInfo.EndOfFile.u.LowPart,
318 TAG_GDITEXT);
319
320 if (Buffer == NULL)
321 {
322 DPRINT("Could not allocate memory for font");
323 NtGdiDeleteObject(NewFont);
324 ZwClose(FileHandle);
325 return 0;
326 }
327
328 /* Load the font into memory chunk */
329
330 Status = ZwReadFile(
331 FileHandle,
332 NULL,
333 NULL,
334 NULL,
335 &Iosb,
336 Buffer,
337 FileStdInfo.EndOfFile.u.LowPart,
338 NULL,
339 NULL);
340
341 if (!NT_SUCCESS(Status))
342 {
343 DPRINT("Could not read the font file into memory");
344 ExFreePool(Buffer);
345 NtGdiDeleteObject(NewFont);
346 ZwClose(FileHandle);
347 return 0;
348 }
349
350 ZwClose(FileHandle);
351
352 IntLockFreeType;
353 Error = FT_New_Memory_Face(
354 library,
355 Buffer,
356 FileStdInfo.EndOfFile.u.LowPart,
357 0,
358 &Face);
359 IntUnLockFreeType;
360
361 if (Error)
362 {
363 if (Error == FT_Err_Unknown_File_Format)
364 DPRINT("Unknown font file format\n");
365 else
366 DPRINT("Error reading font file (error code: %u)\n", Error);
367 ExFreePool(Buffer);
368 NtGdiDeleteObject(NewFont);
369 return 0;
370 }
371
372 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
373 if (!Entry)
374 {
375 FT_Done_Face(Face);
376 ExFreePool(Buffer);
377 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
378 return 0;
379 }
380
381 /* FontGDI->Filename = FileName; perform strcpy */
382 FontGDI->face = Face;
383
384 /* FIXME: Complete text metrics */
385 FontGDI->TextMetric.tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
386 FontGDI->TextMetric.tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
387 FontGDI->TextMetric.tmHeight = (Face->size->metrics.ascender -
388 Face->size->metrics.descender) >> 6;
389
390 DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
391 DPRINT("Num glyphs: %u\n", Face->num_glyphs);
392
393 /* Add this font resource to the font table */
394
395 Entry->hFont = NewFont;
396 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
397 RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name);
398 RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
399
400 if (Characteristics & FR_PRIVATE)
401 {
402 PW32PROCESS Win32Process = PsGetWin32Process();
403 IntLockProcessPrivateFonts(Win32Process);
404 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
405 IntUnLockProcessPrivateFonts(Win32Process);
406 }
407 else
408 {
409 IntLockGlobalFonts;
410 InsertTailList(&FontListHead, &Entry->ListEntry);
411 IntUnLockGlobalFonts;
412 }
413
414 return 1;
415 }
416
417 BOOL FASTCALL
418 IntIsFontRenderingEnabled(VOID)
419 {
420 BOOL Ret = RenderingEnabled;
421 HDC hDC;
422
423 hDC = IntGetScreenDC();
424 if (hDC)
425 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
426
427 return Ret;
428 }
429
430 VOID FASTCALL
431 IntEnableFontRendering(BOOL Enable)
432 {
433 RenderingEnabled = Enable;
434 }
435
436 FT_Render_Mode FASTCALL
437 IntGetFontRenderMode(LOGFONTW *logfont)
438 {
439 switch(logfont->lfQuality)
440 {
441 //case ANTIALIASED_QUALITY:
442 case DEFAULT_QUALITY:
443 return FT_RENDER_MODE_NORMAL;
444 case DRAFT_QUALITY:
445 return FT_RENDER_MODE_LIGHT;
446 //case NONANTIALIASED_QUALITY:
447 case PROOF_QUALITY:
448 return FT_RENDER_MODE_MONO;
449 //case CLEARTYPE_QUALITY:
450 // return FT_RENDER_MODE_LCD;
451 }
452 return FT_RENDER_MODE_MONO;
453 }
454 static NTSTATUS STDCALL
455 GetFontObjectsFromTextObj(PTEXTOBJ TextObj, HFONT *FontHandle, FONTOBJ **FontObj, PFONTGDI *FontGDI)
456 {
457 FONTOBJ *FntObj;
458 NTSTATUS Status = STATUS_SUCCESS;
459
460 ASSERT(NULL != TextObj && NULL != TextObj->GDIFontHandle);
461 if (NULL != TextObj && NULL != TextObj->GDIFontHandle)
462 {
463 if (NULL != FontHandle)
464 {
465 *FontHandle = TextObj->GDIFontHandle;
466 }
467 FntObj = (FONTOBJ*)AccessUserObject((ULONG) TextObj->GDIFontHandle);
468 if (NULL != FontObj)
469 {
470 *FontObj = FntObj;
471 if (NULL == *FontObj)
472 {
473 ASSERT(FALSE);
474 Status = STATUS_INVALID_HANDLE;
475 }
476 }
477 if (NT_SUCCESS(Status) && NULL != FontGDI)
478 {
479 *FontGDI = AccessInternalObjectFromUserObject(FntObj);
480 }
481
482 return Status;
483 }
484
485 return STATUS_INVALID_HANDLE;
486 }
487
488 int
489 STDCALL
490 NtGdiAddFontResource(PUNICODE_STRING Filename, DWORD fl)
491 {
492 UNICODE_STRING SafeFileName;
493 PWSTR src;
494 NTSTATUS Status;
495 int Ret;
496
497 /* Copy the UNICODE_STRING structure */
498 Status = MmCopyFromCaller(&SafeFileName, Filename, sizeof(UNICODE_STRING));
499 if(!NT_SUCCESS(Status))
500 {
501 SetLastNtError(Status);
502 return 0;
503 }
504
505 /* Reserve for prepending '\??\' */
506 SafeFileName.Length += 4 * sizeof(WCHAR);
507 SafeFileName.MaximumLength += 4 * sizeof(WCHAR);
508
509 src = SafeFileName.Buffer;
510 SafeFileName.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, SafeFileName.MaximumLength, TAG_STRING);
511 if(!SafeFileName.Buffer)
512 {
513 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
514 return 0;
515 }
516
517 /* Prepend '\??\' */
518 RtlCopyMemory(SafeFileName.Buffer, L"\\??\\", 4 * sizeof(WCHAR));
519
520 Status = MmCopyFromCaller(SafeFileName.Buffer + 4, src, SafeFileName.MaximumLength - (4 * sizeof(WCHAR)));
521 if(!NT_SUCCESS(Status))
522 {
523 ExFreePool(SafeFileName.Buffer);
524 SetLastNtError(Status);
525 return 0;
526 }
527
528 Ret = IntGdiAddFontResource(&SafeFileName, fl);
529
530 ExFreePool(SafeFileName.Buffer);
531 return Ret;
532 }
533
534 NTSTATUS FASTCALL
535 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
536 {
537 PTEXTOBJ TextObj;
538 NTSTATUS Status = STATUS_SUCCESS;
539
540 *NewFont = TEXTOBJ_AllocText();
541 if (NULL != *NewFont)
542 {
543 TextObj = TEXTOBJ_LockText(*NewFont);
544 if (NULL != TextObj)
545 {
546 memcpy(&TextObj->logfont, lf, sizeof(LOGFONTW));
547 if (lf->lfEscapement != lf->lfOrientation)
548 {
549 /* this should really depend on whether GM_ADVANCED is set */
550 TextObj->logfont.lfOrientation = TextObj->logfont.lfEscapement;
551 }
552 TEXTOBJ_UnlockText(*NewFont);
553 }
554 else
555 {
556 /* FIXME */
557 /* ASSERT(FALSE);*/
558 Status = STATUS_INVALID_HANDLE;
559 }
560 }
561 else
562 {
563 Status = STATUS_NO_MEMORY;
564 }
565
566 return Status;
567 }
568
569 HFONT
570 STDCALL
571 NtGdiCreateFont(int Height,
572 int Width,
573 int Escapement,
574 int Orientation,
575 int Weight,
576 DWORD Italic,
577 DWORD Underline,
578 DWORD StrikeOut,
579 DWORD CharSet,
580 DWORD OutputPrecision,
581 DWORD ClipPrecision,
582 DWORD Quality,
583 DWORD PitchAndFamily,
584 LPCWSTR Face)
585 {
586 LOGFONTW logfont;
587 HFONT NewFont;
588 NTSTATUS Status = STATUS_SUCCESS;
589
590 logfont.lfHeight = Height;
591 logfont.lfWidth = Width;
592 logfont.lfEscapement = Escapement;
593 logfont.lfOrientation = Orientation;
594 logfont.lfWeight = Weight;
595 logfont.lfItalic = Italic;
596 logfont.lfUnderline = Underline;
597 logfont.lfStrikeOut = StrikeOut;
598 logfont.lfCharSet = CharSet;
599 logfont.lfOutPrecision = OutputPrecision;
600 logfont.lfClipPrecision = ClipPrecision;
601 logfont.lfQuality = Quality;
602 logfont.lfPitchAndFamily = PitchAndFamily;
603
604 if (NULL != Face)
605 {
606 int Size = sizeof(logfont.lfFaceName) / sizeof(WCHAR);
607 wcsncpy((wchar_t *)logfont.lfFaceName, Face, Size - 1);
608 /* Be 101% sure to have '\0' at end of string */
609 logfont.lfFaceName[Size - 1] = '\0';
610 }
611 else
612 {
613 logfont.lfFaceName[0] = L'\0';
614 }
615
616 if (NT_SUCCESS(Status))
617 {
618 Status = TextIntCreateFontIndirect(&logfont, &NewFont);
619 }
620
621 return NT_SUCCESS(Status) ? NewFont : NULL;
622 }
623
624 HFONT
625 STDCALL
626 NtGdiCreateFontIndirect(CONST LPLOGFONTW lf)
627 {
628 LOGFONTW SafeLogfont;
629 HFONT NewFont;
630 NTSTATUS Status = STATUS_SUCCESS;
631
632 if (NULL != lf)
633 {
634 Status = MmCopyFromCaller(&SafeLogfont, lf, sizeof(LOGFONTW));
635 if (NT_SUCCESS(Status))
636 {
637 Status = TextIntCreateFontIndirect(&SafeLogfont, &NewFont);
638 }
639 }
640 else
641 {
642 Status = STATUS_INVALID_PARAMETER;
643 }
644
645 return NT_SUCCESS(Status) ? NewFont : NULL;
646 }
647
648 BOOL
649 STDCALL
650 NtGdiCreateScalableFontResource(DWORD Hidden,
651 LPCWSTR FontRes,
652 LPCWSTR FontFile,
653 LPCWSTR CurrentPath)
654 {
655 DPRINT1("NtGdiCreateScalableFontResource - is unimplemented, have a nice day and keep going");
656 return FALSE;
657 }
658
659 /*************************************************************************
660 * TranslateCharsetInfo
661 *
662 * Fills a CHARSETINFO structure for a character set, code page, or
663 * font. This allows making the correspondance between different labelings
664 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
665 * of the same encoding.
666 *
667 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
668 * only one codepage should be set in *Src.
669 *
670 * RETURNS
671 * TRUE on success, FALSE on failure.
672 *
673 */
674 static BOOLEAN STDCALL
675 IntTranslateCharsetInfo(PDWORD Src, /* [in]
676 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
677 if flags == TCI_SRCCHARSET: a character set value
678 if flags == TCI_SRCCODEPAGE: a code page value */
679 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
680 DWORD Flags /* [in] determines interpretation of lpSrc */)
681 {
682 int Index = 0;
683
684 switch (Flags)
685 {
686 case TCI_SRCFONTSIG:
687 while (0 == (*Src >> Index & 0x0001) && Index < MAXTCIINDEX)
688 {
689 Index++;
690 }
691 break;
692 case TCI_SRCCODEPAGE:
693 while ((UINT) (Src) != FontTci[Index].ciACP && Index < MAXTCIINDEX)
694 {
695 Index++;
696 }
697 break;
698 case TCI_SRCCHARSET:
699 while ((UINT) (Src) != FontTci[Index].ciCharset && Index < MAXTCIINDEX)
700 {
701 Index++;
702 }
703 break;
704 default:
705 return FALSE;
706 }
707
708 if (MAXTCIINDEX <= Index || DEFAULT_CHARSET == FontTci[Index].ciCharset)
709 {
710 return FALSE;
711 }
712
713 memcpy(Cs, &FontTci[Index], sizeof(CHARSETINFO));
714
715 return TRUE;
716 }
717
718 BOOL STDCALL
719 NtGdiTranslateCharsetInfo(PDWORD Src,
720 LPCHARSETINFO UnsafeCs,
721 DWORD Flags)
722 {
723 CHARSETINFO Cs;
724 BOOLEAN Ret;
725 NTSTATUS Status;
726
727 Ret = IntTranslateCharsetInfo(Src, &Cs, Flags);
728 if (Ret)
729 {
730 Status = MmCopyToCaller(UnsafeCs, &Cs, sizeof(CHARSETINFO));
731 if (! NT_SUCCESS(Status))
732 {
733 SetLastWin32Error(ERROR_INVALID_PARAMETER);
734 return FALSE;
735 }
736 }
737
738 return (BOOL) Ret;
739 }
740
741
742 /*************************************************************
743 * IntGetOutlineTextMetrics
744 *
745 */
746 static unsigned FASTCALL
747 IntGetOutlineTextMetrics(PFONTGDI FontGDI, UINT Size,
748 OUTLINETEXTMETRICW *Otm)
749 {
750 unsigned Needed;
751 TT_OS2 *pOS2;
752 TT_HoriHeader *pHori;
753 TT_Postscript *pPost;
754 FT_Fixed XScale, YScale;
755 ANSI_STRING FamilyNameA, StyleNameA;
756 UNICODE_STRING FamilyNameW, StyleNameW, Regular;
757 char *Cp;
758 int Ascent, Descent;
759 TEXTMETRICW *TM;
760
761 Needed = sizeof(OUTLINETEXTMETRICW);
762
763 RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name);
764 RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
765
766 RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name);
767 RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
768
769 /* These names should be read from the TT name table */
770
771 /* length of otmpFamilyName */
772 Needed += FamilyNameW.Length + sizeof(WCHAR);
773
774 RtlInitUnicodeString(&Regular, L"regular");
775 /* length of otmpFaceName */
776 if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
777 {
778 Needed += FamilyNameW.Length + sizeof(WCHAR); /* just the family name */
779 }
780 else
781 {
782 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
783 }
784
785 /* length of otmpStyleName */
786 Needed += StyleNameW.Length + sizeof(WCHAR);
787
788 /* length of otmpFullName */
789 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
790
791 if (Size < Needed)
792 {
793 RtlFreeUnicodeString(&FamilyNameW);
794 RtlFreeUnicodeString(&StyleNameW);
795 return Needed;
796 }
797
798 XScale = FontGDI->face->size->metrics.x_scale;
799 YScale = FontGDI->face->size->metrics.y_scale;
800
801 IntLockFreeType;
802 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
803 if (NULL == pOS2)
804 {
805 IntUnLockFreeType;
806 DPRINT1("Can't find OS/2 table - not TT font?\n");
807 RtlFreeUnicodeString(&StyleNameW);
808 RtlFreeUnicodeString(&FamilyNameW);
809 return 0;
810 }
811
812 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
813 if (NULL == pHori)
814 {
815 IntUnLockFreeType;
816 DPRINT1("Can't find HHEA table - not TT font?\n");
817 RtlFreeUnicodeString(&StyleNameW);
818 RtlFreeUnicodeString(&FamilyNameW);
819 return 0;
820 }
821
822 pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* we can live with this failing */
823
824 Otm->otmSize = Needed;
825
826 if (0 == pOS2->usWinAscent + pOS2->usWinDescent)
827 {
828 Ascent = pHori->Ascender;
829 Descent = -pHori->Descender;
830 }
831 else
832 {
833 Ascent = pOS2->usWinAscent;
834 Descent = pOS2->usWinDescent;
835 }
836
837 TM = &Otm->otmTextMetrics;
838 TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
839 TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
840 TM->tmInternalLeading = (FT_MulFix(Ascent + Descent
841 - FontGDI->face->units_per_EM, YScale) + 32) >> 6;
842
843 TM->tmHeight = TM->tmAscent + TM->tmDescent;
844
845 /* MSDN says:
846 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
847 */
848 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
849 - ((Ascent + Descent)
850 - (pHori->Ascender - pHori->Descender)),
851 YScale) + 32) >> 6);
852
853 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
854 if (0 == TM->tmAveCharWidth)
855 {
856 TM->tmAveCharWidth = 1;
857 }
858 TM->tmMaxCharWidth = (FT_MulFix(FontGDI->face->bbox.xMax - FontGDI->face->bbox.xMin,
859 XScale) + 32) >> 6;
860 TM->tmWeight = pOS2->usWeightClass;
861 TM->tmOverhang = 0;
862 TM->tmDigitizedAspectX = 300;
863 TM->tmDigitizedAspectY = 300;
864 TM->tmFirstChar = pOS2->usFirstCharIndex;
865 TM->tmLastChar = pOS2->usLastCharIndex;
866 TM->tmDefaultChar = pOS2->usDefaultChar;
867 TM->tmBreakChar = L'\0' != pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
868 TM->tmItalic = (FontGDI->face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0;
869 TM->tmUnderlined = 0; /* entry in OS2 table */
870 TM->tmStruckOut = 0; /* entry in OS2 table */
871
872 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
873 if (! FT_IS_FIXED_WIDTH(FontGDI->face))
874 {
875 TM->tmPitchAndFamily = TMPF_FIXED_PITCH;
876 }
877 else
878 {
879 TM->tmPitchAndFamily = 0;
880 }
881
882 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
883 {
884 case PAN_FAMILY_SCRIPT:
885 TM->tmPitchAndFamily |= FF_SCRIPT;
886 break;
887 case PAN_FAMILY_DECORATIVE:
888 case PAN_FAMILY_PICTORIAL:
889 TM->tmPitchAndFamily |= FF_DECORATIVE;
890 break;
891 case PAN_FAMILY_TEXT_DISPLAY:
892 if (0 == TM->tmPitchAndFamily) /* fixed */
893 {
894 TM->tmPitchAndFamily = FF_MODERN;
895 }
896 else
897 {
898 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
899 {
900 case PAN_SERIF_NORMAL_SANS:
901 case PAN_SERIF_OBTUSE_SANS:
902 case PAN_SERIF_PERP_SANS:
903 TM->tmPitchAndFamily |= FF_SWISS;
904 break;
905 default:
906 TM->tmPitchAndFamily |= FF_ROMAN;
907 break;
908 }
909 }
910 break;
911 default:
912 TM->tmPitchAndFamily |= FF_DONTCARE;
913 }
914
915 if (FT_IS_SCALABLE(FontGDI->face))
916 {
917 TM->tmPitchAndFamily |= TMPF_VECTOR;
918 }
919 if (FT_IS_SFNT(FontGDI->face))
920 {
921 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
922 }
923
924 #ifndef TODO
925 TM->tmCharSet = DEFAULT_CHARSET;
926 #endif
927
928 Otm->otmFiller = 0;
929 memcpy(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
930 Otm->otmfsSelection = pOS2->fsSelection;
931 Otm->otmfsType = pOS2->fsType;
932 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
933 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
934 Otm->otmItalicAngle = 0; /* POST table */
935 Otm->otmEMSquare = FontGDI->face->units_per_EM;
936 Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
937 Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
938 Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
939 Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
940 Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
941 Otm->otmrcFontBox.left = (FT_MulFix(FontGDI->face->bbox.xMin, XScale) + 32) >> 6;
942 Otm->otmrcFontBox.right = (FT_MulFix(FontGDI->face->bbox.xMax, XScale) + 32) >> 6;
943 Otm->otmrcFontBox.top = (FT_MulFix(FontGDI->face->bbox.yMax, YScale) + 32) >> 6;
944 Otm->otmrcFontBox.bottom = (FT_MulFix(FontGDI->face->bbox.yMin, YScale) + 32) >> 6;
945 Otm->otmMacAscent = 0; /* where do these come from ? */
946 Otm->otmMacDescent = 0;
947 Otm->otmMacLineGap = 0;
948 Otm->otmusMinimumPPEM = 0; /* TT Header */
949 Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
950 Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
951 Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
952 Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
953 Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
954 Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
955 Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
956 Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
957 Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
958 Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
959 if (NULL == pPost)
960 {
961 Otm->otmsUnderscoreSize = 0;
962 Otm->otmsUnderscorePosition = 0;
963 }
964 else
965 {
966 Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
967 Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
968 }
969
970 IntUnLockFreeType;
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 return 0;
1505 }
1506
1507 BOOL STDCALL
1508 NtGdiExtTextOut(
1509 HDC hDC,
1510 INT XStart,
1511 INT YStart,
1512 UINT fuOptions,
1513 CONST RECT *lprc,
1514 LPCWSTR String,
1515 UINT Count,
1516 CONST INT *UnsafeDx)
1517 {
1518 /*
1519 * FIXME:
1520 * Call EngTextOut, which does the real work (calling DrvTextOut where
1521 * appropriate)
1522 */
1523
1524 DC *dc;
1525 SURFOBJ *SurfObj;
1526 BITMAPOBJ *BitmapObj;
1527 int error, glyph_index, n, i;
1528 FT_Face face;
1529 FT_GlyphSlot glyph;
1530 LONGLONG TextLeft, RealXStart;
1531 ULONG TextTop, pitch, previous, BackgroundLeft;
1532 FT_Bool use_kerning;
1533 RECTL DestRect, MaskRect;
1534 POINTL SourcePoint, BrushOrigin;
1535 HBRUSH hBrushFg = NULL;
1536 PGDIBRUSHOBJ BrushFg = NULL;
1537 GDIBRUSHINST BrushFgInst;
1538 HBRUSH hBrushBg = NULL;
1539 PGDIBRUSHOBJ BrushBg = NULL;
1540 GDIBRUSHINST BrushBgInst;
1541 HBITMAP HSourceGlyph;
1542 SURFOBJ *SourceGlyphSurf;
1543 SIZEL bitSize;
1544 FT_CharMap found = 0, charmap;
1545 INT yoff;
1546 FONTOBJ *FontObj;
1547 PFONTGDI FontGDI;
1548 PTEXTOBJ TextObj;
1549 PPALGDI PalDestGDI;
1550 XLATEOBJ *XlateObj, *XlateObj2;
1551 ULONG Mode;
1552 FT_Render_Mode RenderMode;
1553 BOOLEAN Render;
1554 NTSTATUS Status;
1555 INT *Dx = NULL;
1556 POINT Start;
1557
1558 dc = DC_LockDc(hDC);
1559 if (!dc)
1560 {
1561 SetLastWin32Error(ERROR_INVALID_HANDLE);
1562 return FALSE;
1563 }
1564
1565 if (NULL != UnsafeDx && Count > 0)
1566 {
1567 Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
1568 if (NULL == Dx)
1569 {
1570 goto fail;
1571 }
1572 Status = MmCopyFromCaller(Dx, UnsafeDx, Count * sizeof(INT));
1573 if (! NT_SUCCESS(Status))
1574 {
1575 goto fail;
1576 }
1577 }
1578
1579 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
1580 ASSERT(BitmapObj);
1581 SurfObj = &BitmapObj->SurfObj;
1582
1583 Start.x = XStart; Start.y = YStart;
1584 IntLPtoDP(dc, &Start, 1);
1585
1586 RealXStart = (Start.x + dc->w.DCOrgX) << 6;
1587 YStart = Start.y + dc->w.DCOrgY;
1588
1589 /* Create the brushes */
1590 PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
1591 if ( !PalDestGDI )
1592 Mode = PAL_RGB;
1593 else
1594 {
1595 Mode = PalDestGDI->Mode;
1596 PALETTE_UnlockPalette(dc->w.hPalette);
1597 }
1598 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
1599 hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
1600 BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
1601 IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);
1602 if ((fuOptions & ETO_OPAQUE) || dc->w.backgroundMode == OPAQUE)
1603 {
1604 hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor));
1605 if (hBrushBg)
1606 {
1607 BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
1608 IntGdiInitBrushInstance(&BrushBgInst, BrushBg, NULL);
1609 }
1610 else
1611 {
1612 EngDeleteXlate(XlateObj);
1613 goto fail;
1614 }
1615 }
1616 XlateObj2 = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, Mode, NULL, dc->w.hPalette);
1617
1618 SourcePoint.x = 0;
1619 SourcePoint.y = 0;
1620 MaskRect.left = 0;
1621 MaskRect.top = 0;
1622 BrushOrigin.x = 0;
1623 BrushOrigin.y = 0;
1624
1625 if ((fuOptions & ETO_OPAQUE) && lprc)
1626 {
1627 MmCopyFromCaller(&DestRect, lprc, sizeof(RECT));
1628 DestRect.left += dc->w.DCOrgX;
1629 DestRect.top += dc->w.DCOrgY;
1630 DestRect.right += dc->w.DCOrgX;
1631 DestRect.bottom += dc->w.DCOrgY;
1632 IntEngBitBlt(
1633 BitmapObj,
1634 NULL,
1635 NULL,
1636 dc->CombinedClip,
1637 NULL,
1638 &DestRect,
1639 &SourcePoint,
1640 &SourcePoint,
1641 &BrushBgInst.BrushObject,
1642 &BrushOrigin,
1643 PATCOPY);
1644 fuOptions &= ~ETO_OPAQUE;
1645 }
1646 else
1647 {
1648 if (dc->w.backgroundMode == OPAQUE)
1649 {
1650 fuOptions |= ETO_OPAQUE;
1651 }
1652 }
1653
1654 TextObj = TEXTOBJ_LockText(dc->w.hFont);
1655
1656 if (!NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, &FontObj, &FontGDI)))
1657 {
1658 goto fail;
1659 }
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 DPRINT1("WARNING: Could not find desired charmap!\n");
1679 IntLockFreeType;
1680 error = FT_Set_Charmap(face, found);
1681 IntUnLockFreeType;
1682 if (error)
1683 DPRINT1("WARNING: Could not set the charmap!\n");
1684 }
1685
1686 Render = IntIsFontRenderingEnabled();
1687 if (Render)
1688 RenderMode = IntGetFontRenderMode(&TextObj->logfont);
1689 else
1690 RenderMode = FT_RENDER_MODE_MONO;
1691
1692 IntLockFreeType;
1693 error = FT_Set_Pixel_Sizes(
1694 face,
1695 /* FIXME should set character height if neg */
1696 (TextObj->logfont.lfHeight < 0 ?
1697 - TextObj->logfont.lfHeight :
1698 TextObj->logfont.lfHeight),
1699 TextObj->logfont.lfWidth);
1700 IntUnLockFreeType;
1701 if (error)
1702 {
1703 DPRINT1("Error in setting pixel sizes: %u\n", error);
1704 goto fail;
1705 }
1706
1707 /*
1708 * Process the vertical alignment and determine the yoff.
1709 */
1710
1711 if (dc->w.textAlign & TA_BASELINE)
1712 yoff = 0;
1713 else if (dc->w.textAlign & TA_BOTTOM)
1714 yoff = -face->size->metrics.descender >> 6;
1715 else /* TA_TOP */
1716 yoff = face->size->metrics.ascender >> 6;
1717
1718 use_kerning = FT_HAS_KERNING(face);
1719 previous = 0;
1720
1721 /*
1722 * Process the horizontal alignment and modify XStart accordingly.
1723 */
1724
1725 if (dc->w.textAlign & (TA_RIGHT | TA_CENTER))
1726 {
1727 ULONGLONG TextWidth = 0;
1728 LPCWSTR TempText = String;
1729 int Start;
1730
1731 /*
1732 * Calculate width of the text.
1733 */
1734
1735 if (NULL != Dx)
1736 {
1737 Start = Count < 2 ? 0 : Count - 2;
1738 TextWidth = Count < 2 ? 0 : (Dx[Count - 2] << 6);
1739 }
1740 else
1741 {
1742 Start = 0;
1743 }
1744 TempText = String + Start;
1745
1746 for (i = Start; i < Count; i++)
1747 {
1748 IntLockFreeType;
1749 glyph_index = FT_Get_Char_Index(face, *TempText);
1750 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1751 IntUnLockFreeType;
1752
1753 if (error)
1754 {
1755 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1756 }
1757
1758 glyph = face->glyph;
1759
1760 /* retrieve kerning distance */
1761 if (use_kerning && previous && glyph_index)
1762 {
1763 FT_Vector delta;
1764 IntLockFreeType;
1765 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1766 IntUnLockFreeType;
1767 TextWidth += delta.x;
1768 }
1769
1770 TextWidth += glyph->advance.x;
1771
1772 previous = glyph_index;
1773 TempText++;
1774 }
1775
1776 previous = 0;
1777
1778 if (dc->w.textAlign & TA_RIGHT)
1779 {
1780 RealXStart -= TextWidth;
1781 }
1782 else
1783 {
1784 RealXStart -= TextWidth / 2;
1785 }
1786 }
1787
1788 TextLeft = RealXStart;
1789 TextTop = YStart;
1790 BackgroundLeft = (RealXStart + 32) >> 6;
1791
1792 /*
1793 * The main rendering loop.
1794 */
1795
1796 for (i = 0; i < Count; i++)
1797 {
1798 IntLockFreeType;
1799 glyph_index = FT_Get_Char_Index(face, *String);
1800 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1801 IntUnLockFreeType;
1802
1803 if (error)
1804 {
1805 EngDeleteXlate(XlateObj);
1806 EngDeleteXlate(XlateObj2);
1807 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1808 goto fail;
1809 }
1810
1811 glyph = face->glyph;
1812
1813 /* retrieve kerning distance and move pen position */
1814 if (use_kerning && previous && glyph_index && NULL == Dx)
1815 {
1816 FT_Vector delta;
1817 IntLockFreeType;
1818 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1819 IntUnLockFreeType;
1820 TextLeft += delta.x;
1821 }
1822
1823 if (glyph->format == ft_glyph_format_outline)
1824 {
1825 IntLockFreeType;
1826 error = FT_Render_Glyph(glyph, RenderMode);
1827 IntUnLockFreeType;
1828 if (error)
1829 {
1830 EngDeleteXlate(XlateObj);
1831 EngDeleteXlate(XlateObj2);
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 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 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
1879
1880 /*
1881 * Use the font data as a mask to paint onto the DCs surface using a
1882 * brush.
1883 */
1884
1885 IntEngMaskBlt(
1886 SurfObj,
1887 SourceGlyphSurf,
1888 dc->CombinedClip,
1889 XlateObj,
1890 XlateObj2,
1891 &DestRect,
1892 &SourcePoint,
1893 (PPOINTL)&MaskRect,
1894 &BrushFgInst.BrushObject,
1895 &BrushOrigin);
1896
1897 EngUnlockSurface(SourceGlyphSurf);
1898 EngDeleteSurface((HSURF)HSourceGlyph);
1899
1900 if (NULL == Dx)
1901 {
1902 TextLeft += glyph->advance.x;
1903 }
1904 else
1905 {
1906 TextLeft += Dx[i] << 6;
1907 }
1908 previous = glyph_index;
1909
1910 String++;
1911 }
1912
1913 EngDeleteXlate(XlateObj);
1914 EngDeleteXlate(XlateObj2);
1915 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
1916 TEXTOBJ_UnlockText(dc->w.hFont);
1917 if (hBrushBg != NULL)
1918 {
1919 BRUSHOBJ_UnlockBrush(hBrushBg);
1920 NtGdiDeleteObject(hBrushBg);
1921 }
1922 BRUSHOBJ_UnlockBrush(hBrushFg);
1923 NtGdiDeleteObject(hBrushFg);
1924 if (NULL != Dx)
1925 {
1926 ExFreePool(Dx);
1927 }
1928 DC_UnlockDc(hDC);
1929
1930 return TRUE;
1931
1932 fail:
1933 TEXTOBJ_UnlockText(dc->w.hFont);
1934 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
1935 if (hBrushBg != NULL)
1936 {
1937 BRUSHOBJ_UnlockBrush(hBrushBg);
1938 NtGdiDeleteObject(hBrushBg);
1939 }
1940 if (hBrushFg != NULL)
1941 {
1942 BRUSHOBJ_UnlockBrush(hBrushFg);
1943 NtGdiDeleteObject(hBrushFg);
1944 }
1945 if (NULL != Dx)
1946 {
1947 ExFreePool(Dx);
1948 }
1949 DC_UnlockDc(hDC);
1950
1951 return FALSE;
1952 }
1953
1954 BOOL
1955 STDCALL
1956 NtGdiGetAspectRatioFilterEx(HDC hDC,
1957 LPSIZE AspectRatio)
1958 {
1959 UNIMPLEMENTED;
1960 return FALSE;
1961 }
1962
1963 BOOL
1964 STDCALL
1965 NtGdiGetCharABCWidths(HDC hDC,
1966 UINT FirstChar,
1967 UINT LastChar,
1968 LPABC abc)
1969 {
1970 DPRINT1("NtGdiGetCharABCWidths Is unimplemented, keep going anyway\n");
1971 return 1;
1972 }
1973
1974 BOOL
1975 STDCALL
1976 NtGdiGetCharABCWidthsFloat(HDC hDC,
1977 UINT FirstChar,
1978 UINT LastChar,
1979 LPABCFLOAT abcF)
1980 {
1981 UNIMPLEMENTED;
1982 return FALSE;
1983 }
1984
1985 DWORD
1986 STDCALL
1987 NtGdiGetCharacterPlacement(HDC hDC,
1988 LPCWSTR String,
1989 int Count,
1990 int MaxExtent,
1991 LPGCP_RESULTSW Results,
1992 DWORD Flags)
1993 {
1994 UNIMPLEMENTED;
1995 return 0;
1996 }
1997
1998 BOOL
1999 STDCALL
2000 NtGdiGetCharWidth32(HDC hDC,
2001 UINT FirstChar,
2002 UINT LastChar,
2003 LPINT Buffer)
2004 {
2005 LPINT SafeBuffer;
2006 PDC dc;
2007 PTEXTOBJ TextObj;
2008 PFONTGDI FontGDI;
2009 FT_Face face;
2010 FT_CharMap charmap, found = NULL;
2011 UINT i, glyph_index, BufferSize;
2012 HFONT hFont = 0;
2013
2014 if (LastChar < FirstChar)
2015 {
2016 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2017 return FALSE;
2018 }
2019
2020 BufferSize = (LastChar - FirstChar + 1) * sizeof(INT);
2021 SafeBuffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
2022 if (SafeBuffer == NULL)
2023 {
2024 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2025 return FALSE;
2026 }
2027
2028 dc = DC_LockDc(hDC);
2029 if (dc == NULL)
2030 {
2031 ExFreePool(SafeBuffer);
2032 SetLastWin32Error(ERROR_INVALID_HANDLE);
2033 return FALSE;
2034 }
2035 hFont = dc->w.hFont;
2036 TextObj = TEXTOBJ_LockText(hFont);
2037 DC_UnlockDc(hDC);
2038
2039 if (TextObj == NULL)
2040 {
2041 ExFreePool(SafeBuffer);
2042 SetLastWin32Error(ERROR_INVALID_HANDLE);
2043 return FALSE;
2044 }
2045
2046 if (!NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI)))
2047 {
2048 ExFreePool(SafeBuffer);
2049 SetLastWin32Error(ERROR_INVALID_HANDLE);
2050 TEXTOBJ_UnlockText(hFont);
2051 return FALSE;
2052 }
2053
2054 face = FontGDI->face;
2055 if (face->charmap == NULL)
2056 {
2057 for (i = 0; i < face->num_charmaps; i++)
2058 {
2059 charmap = face->charmaps[i];
2060 if (charmap->encoding != 0)
2061 {
2062 found = charmap;
2063 break;
2064 }
2065 }
2066
2067 if (!found)
2068 {
2069 DPRINT1("WARNING: Could not find desired charmap!\n");
2070 ExFreePool(SafeBuffer);
2071 SetLastWin32Error(ERROR_INVALID_HANDLE);
2072 return FALSE;
2073 }
2074
2075 IntLockFreeType;
2076 FT_Set_Charmap(face, found);
2077 IntUnLockFreeType;
2078 }
2079
2080 IntLockFreeType;
2081 FT_Set_Pixel_Sizes(face,
2082 /* FIXME should set character height if neg */
2083 (TextObj->logfont.lfHeight < 0 ?
2084 - TextObj->logfont.lfHeight :
2085 TextObj->logfont.lfHeight),
2086 TextObj->logfont.lfWidth);
2087
2088 for (i = FirstChar; i <= LastChar; i++)
2089 {
2090 glyph_index = FT_Get_Char_Index(face, i);
2091 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2092 SafeBuffer[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
2093 }
2094 IntUnLockFreeType;
2095 TEXTOBJ_UnlockText(hFont);
2096 MmCopyToCaller(Buffer, SafeBuffer, BufferSize);
2097 ExFreePool(SafeBuffer);
2098 return TRUE;
2099 }
2100
2101 BOOL
2102 STDCALL
2103 NtGdiGetCharWidthFloat(HDC hDC,
2104 UINT FirstChar,
2105 UINT LastChar,
2106 PFLOAT Buffer)
2107 {
2108 UNIMPLEMENTED;
2109 return FALSE;
2110 }
2111
2112 DWORD
2113 STDCALL
2114 NtGdiGetFontLanguageInfo(HDC hDC)
2115 {
2116 UNIMPLEMENTED;
2117 return 0;
2118 }
2119
2120 DWORD
2121 STDCALL
2122 NtGdiGetGlyphOutline(HDC hDC,
2123 UINT Char,
2124 UINT Format,
2125 LPGLYPHMETRICS gm,
2126 DWORD Bufsize,
2127 LPVOID Buffer,
2128 CONST LPMAT2 mat2)
2129 {
2130 UNIMPLEMENTED;
2131 return 0;
2132 }
2133
2134 DWORD
2135 STDCALL
2136 NtGdiGetKerningPairs(HDC hDC,
2137 DWORD NumPairs,
2138 LPKERNINGPAIR krnpair)
2139 {
2140 UNIMPLEMENTED;
2141 return 0;
2142 }
2143
2144 UINT
2145 STDCALL
2146 NtGdiGetOutlineTextMetrics(HDC hDC,
2147 UINT Data,
2148 LPOUTLINETEXTMETRICW otm)
2149 {
2150 UNIMPLEMENTED;
2151 return 0;
2152 }
2153
2154 BOOL
2155 STDCALL
2156 NtGdiGetRasterizerCaps(LPRASTERIZER_STATUS rs,
2157 UINT Size)
2158 {
2159 UNIMPLEMENTED;
2160 return FALSE;
2161 }
2162
2163 UINT
2164 STDCALL
2165 NtGdiGetTextCharset(HDC hDC)
2166 {
2167 UNIMPLEMENTED;
2168 return 0;
2169 }
2170
2171 UINT
2172 STDCALL
2173 NtGdiGetTextCharsetInfo(HDC hDC,
2174 LPFONTSIGNATURE Sig,
2175 DWORD Flags)
2176 {
2177 UNIMPLEMENTED;
2178 return 0;
2179 }
2180
2181 static BOOL
2182 FASTCALL
2183 TextIntGetTextExtentPoint(HDC hDC,
2184 PTEXTOBJ TextObj,
2185 LPCWSTR String,
2186 int Count,
2187 int MaxExtent,
2188 LPINT Fit,
2189 LPINT Dx,
2190 LPSIZE Size)
2191 {
2192 PFONTGDI FontGDI;
2193 FT_Face face;
2194 FT_GlyphSlot glyph;
2195 INT error, n, glyph_index, i, previous;
2196 ULONGLONG TotalWidth = 0;
2197 FT_CharMap charmap, found = NULL;
2198 BOOL use_kerning;
2199
2200 if (!NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI)))
2201 {
2202 return FALSE;
2203 }
2204
2205 face = FontGDI->face;
2206 if (NULL != Fit)
2207 {
2208 *Fit = 0;
2209 }
2210
2211 if (face->charmap == NULL)
2212 {
2213 DPRINT("WARNING: No charmap selected!\n");
2214 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2215
2216 for (n = 0; n < face->num_charmaps; n++)
2217 {
2218 charmap = face->charmaps[n];
2219 DPRINT("found charmap encoding: %u\n", charmap->encoding);
2220 if (charmap->encoding != 0)
2221 {
2222 found = charmap;
2223 break;
2224 }
2225 }
2226
2227 if (! found)
2228 {
2229 DPRINT1("WARNING: Could not find desired charmap!\n");
2230 }
2231
2232 IntLockFreeType;
2233 error = FT_Set_Charmap(face, found);
2234 IntUnLockFreeType;
2235 if (error)
2236 {
2237 DPRINT1("WARNING: Could not set the charmap!\n");
2238 }
2239 }
2240
2241 IntLockFreeType;
2242 error = FT_Set_Pixel_Sizes(face,
2243 /* FIXME should set character height if neg */
2244 (TextObj->logfont.lfHeight < 0 ?
2245 - TextObj->logfont.lfHeight :
2246 TextObj->logfont.lfHeight),
2247 TextObj->logfont.lfWidth);
2248 IntUnLockFreeType;
2249 if (error)
2250 {
2251 DPRINT1("Error in setting pixel sizes: %u\n", error);
2252 }
2253
2254 use_kerning = FT_HAS_KERNING(face);
2255 previous = 0;
2256
2257 for (i = 0; i < Count; i++)
2258 {
2259 IntLockFreeType;
2260 glyph_index = FT_Get_Char_Index(face, *String);
2261 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2262 IntUnLockFreeType;
2263 if (error)
2264 {
2265 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
2266 }
2267 glyph = face->glyph;
2268
2269 /* retrieve kerning distance */
2270 if (use_kerning && previous && glyph_index)
2271 {
2272 FT_Vector delta;
2273 IntLockFreeType;
2274 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
2275 IntUnLockFreeType;
2276 TotalWidth += delta.x;
2277 }
2278
2279 TotalWidth += glyph->advance.x;
2280
2281 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
2282 {
2283 *Fit = i + 1;
2284 }
2285 if (NULL != Dx)
2286 {
2287 Dx[i] = (TotalWidth + 32) >> 6;
2288 }
2289
2290 previous = glyph_index;
2291 String++;
2292 }
2293
2294 Size->cx = (TotalWidth + 32) >> 6;
2295 Size->cy = (TextObj->logfont.lfHeight < 0 ? - TextObj->logfont.lfHeight : TextObj->logfont.lfHeight);
2296 Size->cy = EngMulDiv(Size->cy, NtGdiGetDeviceCaps(hDC, LOGPIXELSY), 72);
2297
2298 return TRUE;
2299 }
2300
2301 BOOL
2302 STDCALL
2303 NtGdiGetTextExtentExPoint(HDC hDC,
2304 LPCWSTR UnsafeString,
2305 int Count,
2306 int MaxExtent,
2307 LPINT UnsafeFit,
2308 LPINT UnsafeDx,
2309 LPSIZE UnsafeSize)
2310 {
2311 PDC dc;
2312 LPWSTR String;
2313 SIZE Size;
2314 NTSTATUS Status;
2315 BOOLEAN Result;
2316 INT Fit;
2317 LPINT Dx;
2318 PTEXTOBJ TextObj;
2319
2320 if (Count < 0)
2321 {
2322 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2323 return FALSE;
2324 }
2325 if (0 == Count)
2326 {
2327 Size.cx = 0;
2328 Size.cy = 0;
2329 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
2330 if (! NT_SUCCESS(Status))
2331 {
2332 SetLastNtError(Status);
2333 return FALSE;
2334 }
2335 return TRUE;
2336 }
2337
2338 String = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), TAG_GDITEXT);
2339 if (NULL == String)
2340 {
2341 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2342 return FALSE;
2343 }
2344
2345 if (NULL != UnsafeDx)
2346 {
2347 Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
2348 if (NULL == Dx)
2349 {
2350 ExFreePool(String);
2351 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2352 return FALSE;
2353 }
2354 }
2355 else
2356 {
2357 Dx = NULL;
2358 }
2359
2360 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
2361 if (! NT_SUCCESS(Status))
2362 {
2363 if (NULL != Dx)
2364 {
2365 ExFreePool(Dx);
2366 }
2367 ExFreePool(String);
2368 SetLastNtError(Status);
2369 return FALSE;
2370 }
2371
2372 dc = DC_LockDc(hDC);
2373 if (NULL == dc)
2374 {
2375 if (NULL != Dx)
2376 {
2377 ExFreePool(Dx);
2378 }
2379 ExFreePool(String);
2380 SetLastWin32Error(ERROR_INVALID_HANDLE);
2381 return FALSE;
2382 }
2383 TextObj = TEXTOBJ_LockText(dc->w.hFont);
2384 DC_UnlockDc(hDC);
2385 Result = TextIntGetTextExtentPoint(hDC, TextObj, String, Count, MaxExtent,
2386 NULL == UnsafeFit ? NULL : &Fit, Dx, &Size);
2387 TEXTOBJ_UnlockText(dc->w.hFont);
2388
2389 ExFreePool(String);
2390 if (! Result)
2391 {
2392 if (NULL != Dx)
2393 {
2394 ExFreePool(Dx);
2395 }
2396 return FALSE;
2397 }
2398
2399 if (NULL != UnsafeFit)
2400 {
2401 Status = MmCopyToCaller(UnsafeFit, &Fit, sizeof(INT));
2402 if (! NT_SUCCESS(Status))
2403 {
2404 if (NULL != Dx)
2405 {
2406 ExFreePool(Dx);
2407 }
2408 SetLastNtError(Status);
2409 return FALSE;
2410 }
2411 }
2412
2413 if (NULL != UnsafeDx)
2414 {
2415 Status = MmCopyToCaller(UnsafeDx, Dx, Count * sizeof(INT));
2416 if (! NT_SUCCESS(Status))
2417 {
2418 if (NULL != Dx)
2419 {
2420 ExFreePool(Dx);
2421 }
2422 SetLastNtError(Status);
2423 return FALSE;
2424 }
2425 }
2426 if (NULL != Dx)
2427 {
2428 ExFreePool(Dx);
2429 }
2430
2431 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
2432 if (! NT_SUCCESS(Status))
2433 {
2434 SetLastNtError(Status);
2435 return FALSE;
2436 }
2437
2438 return TRUE;
2439 }
2440
2441 BOOL
2442 STDCALL
2443 NtGdiGetTextExtentPoint(HDC hDC,
2444 LPCWSTR String,
2445 int Count,
2446 LPSIZE Size)
2447 {
2448 return NtGdiGetTextExtentExPoint(hDC, String, Count, 0, NULL, NULL, Size);
2449 }
2450
2451 BOOL
2452 STDCALL
2453 NtGdiGetTextExtentPoint32(HDC hDC,
2454 LPCWSTR UnsafeString,
2455 int Count,
2456 LPSIZE UnsafeSize)
2457 {
2458 PDC dc;
2459 LPWSTR String;
2460 SIZE Size;
2461 NTSTATUS Status;
2462 BOOLEAN Result;
2463 PTEXTOBJ TextObj;
2464
2465 if (Count < 0)
2466 {
2467 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2468 return FALSE;
2469 }
2470 if (0 == Count)
2471 {
2472 Size.cx = 0;
2473 Size.cy = 0;
2474 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
2475 if (! NT_SUCCESS(Status))
2476 {
2477 SetLastNtError(Status);
2478 return FALSE;
2479 }
2480 return TRUE;
2481 }
2482
2483 String = ExAllocatePool(PagedPool, Count * sizeof(WCHAR));
2484 if (NULL == String)
2485 {
2486 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2487 return FALSE;
2488 }
2489
2490 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
2491 if (! NT_SUCCESS(Status))
2492 {
2493 ExFreePool(String);
2494 SetLastNtError(Status);
2495 return FALSE;
2496 }
2497
2498 dc = DC_LockDc(hDC);
2499 if (NULL == dc)
2500 {
2501 ExFreePool(String);
2502 SetLastWin32Error(ERROR_INVALID_HANDLE);
2503 return FALSE;
2504 }
2505 TextObj = TEXTOBJ_LockText(dc->w.hFont);
2506 DC_UnlockDc(hDC);
2507 Result = TextIntGetTextExtentPoint (
2508 hDC, TextObj, String, Count, 0, NULL, NULL, &Size);
2509 dc = DC_LockDc(hDC);
2510 ASSERT(dc); // it succeeded earlier, it should now, too
2511 TEXTOBJ_UnlockText(dc->w.hFont);
2512 DC_UnlockDc(hDC);
2513
2514 ExFreePool(String);
2515 if (! Result)
2516 {
2517 return FALSE;
2518 }
2519
2520 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
2521 if (! NT_SUCCESS(Status))
2522 {
2523 SetLastNtError(Status);
2524 return FALSE;
2525 }
2526
2527 return TRUE;
2528 }
2529
2530 INT STDCALL
2531 NtGdiGetTextFace(HDC hDC, INT Count, LPWSTR FaceName)
2532 {
2533 PDC Dc;
2534 PTEXTOBJ TextObj;
2535 NTSTATUS Status;
2536
2537 Dc = DC_LockDc(hDC);
2538 if (Dc == NULL)
2539 {
2540 SetLastWin32Error(ERROR_INVALID_HANDLE);
2541 return FALSE;
2542 }
2543 TextObj = TEXTOBJ_LockText(Dc->w.hFont);
2544 DC_UnlockDc(hDC);
2545
2546 Count = min(Count, wcslen(TextObj->logfont.lfFaceName));
2547 Status = MmCopyToCaller(FaceName, TextObj->logfont.lfFaceName, Count * sizeof(WCHAR));
2548 if (!NT_SUCCESS(Status))
2549 {
2550 SetLastNtError(Status);
2551 return 0;
2552 }
2553
2554 return Count;
2555 }
2556
2557 BOOL
2558 STDCALL
2559 NtGdiGetTextMetrics(HDC hDC,
2560 LPTEXTMETRICW tm)
2561 {
2562 PDC dc;
2563 PTEXTOBJ TextObj;
2564 PFONTGDI FontGDI;
2565 NTSTATUS Status = STATUS_SUCCESS;
2566 TEXTMETRICW SafeTm;
2567 FT_Face Face;
2568 TT_OS2 *pOS2;
2569 ULONG Error;
2570
2571 if (NULL == tm)
2572 {
2573 SetLastWin32Error(STATUS_INVALID_PARAMETER);
2574 return FALSE;
2575 }
2576
2577 if(!(dc = DC_LockDc(hDC)))
2578 {
2579 SetLastWin32Error(ERROR_INVALID_HANDLE);
2580 return FALSE;
2581 }
2582
2583 TextObj = TEXTOBJ_LockText(dc->w.hFont);
2584 if (NULL != TextObj)
2585 {
2586 Status = GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI);
2587 if (NT_SUCCESS(Status))
2588 {
2589 Face = FontGDI->face;
2590 IntLockFreeType;
2591 Error = FT_Set_Pixel_Sizes(Face,
2592 /* FIXME should set character height if neg */
2593 (TextObj->logfont.lfHeight < 0 ?
2594 - TextObj->logfont.lfHeight :
2595 TextObj->logfont.lfHeight),
2596 TextObj->logfont.lfWidth);
2597 IntUnLockFreeType;
2598 if (0 != Error)
2599 {
2600 DPRINT1("Error in setting pixel sizes: %u\n", Error);
2601 Status = STATUS_UNSUCCESSFUL;
2602 }
2603 else
2604 {
2605 memcpy(&SafeTm, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
2606 IntLockFreeType;
2607 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2608 IntUnLockFreeType;
2609 if (NULL == pOS2)
2610 {
2611 DPRINT1("Can't find OS/2 table - not TT font?\n");
2612 Status = STATUS_UNSUCCESSFUL;
2613 }
2614 else
2615 {
2616 SafeTm.tmAveCharWidth = (pOS2->xAvgCharWidth + 32) >> 6;
2617 }
2618 SafeTm.tmAscent = (Face->size->metrics.ascender + 32) >> 6; // units above baseline
2619 SafeTm.tmDescent = (32 - Face->size->metrics.descender) >> 6; // units below baseline
2620 SafeTm.tmHeight = SafeTm.tmAscent + SafeTm.tmDescent;
2621 SafeTm.tmMaxCharWidth = (Face->size->metrics.max_advance + 32) >> 6;
2622 if (FT_IS_SFNT(FontGDI->face))
2623 {
2624 SafeTm.tmPitchAndFamily |= TMPF_TRUETYPE;
2625 }
2626 Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
2627 }
2628 }
2629 TEXTOBJ_UnlockText(dc->w.hFont);
2630 }
2631 else
2632 {
2633 ASSERT(FALSE);
2634 Status = STATUS_INVALID_HANDLE;
2635 }
2636 DC_UnlockDc(hDC);
2637
2638 if(!NT_SUCCESS(Status))
2639 {
2640 SetLastNtError(Status);
2641 return FALSE;
2642 }
2643
2644 return TRUE;
2645 }
2646
2647 BOOL
2648 STDCALL
2649 NtGdiPolyTextOut(HDC hDC,
2650 CONST LPPOLYTEXTW txt,
2651 int Count)
2652 {
2653 UNIMPLEMENTED;
2654 return FALSE;
2655 }
2656
2657 BOOL
2658 STDCALL
2659 NtGdiRemoveFontResource(LPCWSTR FileName)
2660 {
2661 UNIMPLEMENTED;
2662 return FALSE;
2663 }
2664
2665 DWORD
2666 STDCALL
2667 NtGdiSetMapperFlags(HDC hDC,
2668 DWORD Flag)
2669 {
2670 UNIMPLEMENTED;
2671 return 0;
2672 }
2673
2674 UINT
2675 STDCALL
2676 NtGdiSetTextAlign(HDC hDC,
2677 UINT Mode)
2678 {
2679 UINT prevAlign;
2680 DC *dc;
2681
2682 dc = DC_LockDc(hDC);
2683 if (!dc)
2684 {
2685 SetLastWin32Error(ERROR_INVALID_HANDLE);
2686 return GDI_ERROR;
2687 }
2688 prevAlign = dc->w.textAlign;
2689 dc->w.textAlign = Mode;
2690 DC_UnlockDc( hDC );
2691 return prevAlign;
2692 }
2693
2694 COLORREF
2695 STDCALL
2696 NtGdiSetTextColor(HDC hDC,
2697 COLORREF color)
2698 {
2699 COLORREF oldColor;
2700 PDC dc = DC_LockDc(hDC);
2701 HBRUSH hBrush;
2702
2703 if (!dc)
2704 {
2705 SetLastWin32Error(ERROR_INVALID_HANDLE);
2706 return CLR_INVALID;
2707 }
2708
2709 oldColor = dc->w.textColor;
2710 dc->w.textColor = color;
2711 hBrush = dc->w.hBrush;
2712 DC_UnlockDc( hDC );
2713 NtGdiSelectObject(hDC, hBrush);
2714 return oldColor;
2715 }
2716
2717 BOOL
2718 STDCALL
2719 NtGdiSetTextJustification(HDC hDC,
2720 int BreakExtra,
2721 int BreakCount)
2722 {
2723 UNIMPLEMENTED;
2724 return FALSE;
2725 }
2726
2727 BOOL STDCALL
2728 NtGdiTextOut(
2729 HDC hDC,
2730 INT XStart,
2731 INT YStart,
2732 LPCWSTR String,
2733 INT Count)
2734 {
2735 return NtGdiExtTextOut(hDC, XStart, YStart, 0, NULL, String, Count, NULL);
2736 }
2737
2738 DWORD STDCALL
2739 NtGdiGetFontData(
2740 HDC hDC,
2741 DWORD Table,
2742 DWORD Offset,
2743 LPVOID Buffer,
2744 DWORD Size)
2745 {
2746 PDC Dc;
2747 HFONT hFont;
2748 PTEXTOBJ TextObj;
2749 PFONTGDI FontGdi;
2750 DWORD Result = GDI_ERROR;
2751 NTSTATUS Status;
2752
2753 Dc = DC_LockDc(hDC);
2754 if (Dc == NULL)
2755 {
2756 SetLastWin32Error(ERROR_INVALID_HANDLE);
2757 return GDI_ERROR;
2758 }
2759 hFont = Dc->w.hFont;
2760 TextObj = TEXTOBJ_LockText(hFont);
2761 DC_UnlockDc(hDC);
2762
2763 if (TextObj == NULL)
2764 {
2765 SetLastWin32Error(ERROR_INVALID_HANDLE);
2766 return GDI_ERROR;
2767 }
2768
2769 Status = GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGdi);
2770 if (NT_SUCCESS(Status))
2771 {
2772 IntLockFreeType;
2773
2774 if (FT_IS_SFNT(FontGdi->face))
2775 {
2776 if (Table)
2777 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
2778 (Table << 8 & 0xFF0000);
2779
2780 if (Buffer == NULL)
2781 Size = 0;
2782
2783 if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
2784 Result = Size;
2785 }
2786
2787 IntUnLockFreeType;
2788 }
2789
2790 TEXTOBJ_UnlockText(hFont);
2791
2792 return Result;
2793 }
2794
2795 static UINT FASTCALL
2796 GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
2797 {
2798 ANSI_STRING EntryFaceNameA;
2799 UNICODE_STRING EntryFaceNameW;
2800 unsigned Size;
2801 OUTLINETEXTMETRICW *Otm;
2802 LONG WeightDiff;
2803 NTSTATUS Status;
2804 UINT Score = 1;
2805
2806 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
2807 Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2808 if (NT_SUCCESS(Status))
2809 {
2810 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2811 {
2812 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2813 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2814 }
2815 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
2816 {
2817 Score += 49;
2818 }
2819 RtlFreeUnicodeString(&EntryFaceNameW);
2820 }
2821
2822 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2823 Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
2824 if (NULL == Otm)
2825 {
2826 return Score;
2827 }
2828 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2829
2830 if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
2831 (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
2832 {
2833 Score += 25;
2834 }
2835 if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
2836 {
2837 WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
2838 }
2839 else
2840 {
2841 WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
2842 }
2843 Score += (1000 - WeightDiff) / (1000 / 25);
2844
2845 ExFreePool(Otm);
2846
2847 return Score;
2848 }
2849
2850 static VOID FASTCALL
2851 FindBestFontFromList(HFONT *Font, UINT *MatchScore, LOGFONTW *LogFont,
2852 PUNICODE_STRING FaceName, PLIST_ENTRY Head)
2853 {
2854 PLIST_ENTRY Entry;
2855 PFONT_ENTRY CurrentEntry;
2856 PFONTGDI FontGDI;
2857 UINT Score;
2858
2859 Entry = Head->Flink;
2860 while (Entry != Head)
2861 {
2862 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2863 if (NULL == (FontGDI = AccessInternalObject((ULONG) CurrentEntry->hFont)))
2864 {
2865 Entry = Entry->Flink;
2866 continue;
2867 }
2868 Score = GetFontScore(LogFont, FaceName, FontGDI);
2869 if (*MatchScore == 0 || *MatchScore < Score)
2870 {
2871 *Font = CurrentEntry->hFont;
2872 *MatchScore = Score;
2873 }
2874 Entry = Entry->Flink;
2875 }
2876 }
2877
2878 static BOOLEAN FASTCALL
2879 SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
2880 LPCWSTR Key)
2881 {
2882 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
2883 NTSTATUS Status;
2884 UNICODE_STRING Value;
2885
2886 RtlInitUnicodeString(&Value, NULL);
2887
2888 QueryTable[0].QueryRoutine = NULL;
2889 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
2890 RTL_QUERY_REGISTRY_REQUIRED;
2891 QueryTable[0].Name = FaceName->Buffer;
2892 QueryTable[0].EntryContext = &Value;
2893 QueryTable[0].DefaultType = REG_NONE;
2894 QueryTable[0].DefaultData = NULL;
2895 QueryTable[0].DefaultLength = 0;
2896
2897 QueryTable[1].QueryRoutine = NULL;
2898 QueryTable[1].Name = NULL;
2899
2900 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2901 Key,
2902 QueryTable,
2903 NULL,
2904 NULL);
2905 if (NT_SUCCESS(Status))
2906 {
2907 RtlFreeUnicodeString(FaceName);
2908 *FaceName = Value;
2909 }
2910
2911 return NT_SUCCESS(Status);
2912 }
2913
2914 static void FASTCALL
2915 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
2916 {
2917 if (10 < Level) /* Enough is enough */
2918 {
2919 return;
2920 }
2921
2922 if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
2923 SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
2924 {
2925 SubstituteFontFamily(FaceName, Level + 1);
2926 }
2927 }
2928
2929 NTSTATUS FASTCALL
2930 TextIntRealizeFont(HFONT FontHandle)
2931 {
2932 NTSTATUS Status = STATUS_SUCCESS;
2933 PTEXTOBJ TextObj;
2934 UNICODE_STRING FaceName;
2935 PW32PROCESS Win32Process;
2936 UINT MatchScore;
2937
2938 TextObj = TEXTOBJ_LockText(FontHandle);
2939 if (NULL == TextObj)
2940 {
2941 return STATUS_INVALID_HANDLE;
2942 }
2943
2944 if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.lfFaceName))
2945 {
2946 TEXTOBJ_UnlockText(FontHandle);
2947 return STATUS_NO_MEMORY;
2948 }
2949 SubstituteFontFamily(&FaceName, 0);
2950 MatchScore = 0;
2951 TextObj->GDIFontHandle = NULL;
2952
2953 /* First search private fonts */
2954 Win32Process = PsGetWin32Process();
2955 IntLockProcessPrivateFonts(Win32Process);
2956 FindBestFontFromList(&TextObj->GDIFontHandle, &MatchScore,
2957 &TextObj->logfont, &FaceName,
2958 &Win32Process->PrivateFontListHead);
2959 IntUnLockProcessPrivateFonts(Win32Process);
2960
2961 /* Search system fonts */
2962 IntLockGlobalFonts;
2963 FindBestFontFromList(&TextObj->GDIFontHandle, &MatchScore,
2964 &TextObj->logfont, &FaceName,
2965 &FontListHead);
2966 IntUnLockGlobalFonts;
2967
2968 if (NULL == TextObj->GDIFontHandle)
2969 {
2970 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
2971 TextObj->logfont.lfFaceName);
2972 Status = STATUS_NOT_FOUND;
2973 }
2974
2975 RtlFreeUnicodeString(&FaceName);
2976 TEXTOBJ_UnlockText(FontHandle);
2977
2978 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->GDIFontHandle)) != 0);
2979
2980 return Status;
2981 }
2982
2983 INT FASTCALL
2984 FontGetObject(PTEXTOBJ Font, INT Count, PVOID Buffer)
2985 {
2986 if (Count < sizeof(LOGFONTW))
2987 {
2988 SetLastWin32Error(ERROR_BUFFER_OVERFLOW);
2989 return 0;
2990 }
2991
2992 RtlCopyMemory(Buffer, &Font->logfont, sizeof(LOGFONTW));
2993
2994 return sizeof(LOGFONTW);
2995 }
2996
2997 /* EOF */