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