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