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