attempt to fix a few message queue and timer bugs
[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.108 2004/07/30 09:16:06 weiden 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 ULONG TextLeft, TextTop, pitch, previous, BackgroundLeft;
1525 FT_Bool use_kerning;
1526 RECTL DestRect, MaskRect;
1527 POINTL SourcePoint, BrushOrigin;
1528 HBRUSH hBrushFg = NULL;
1529 PGDIBRUSHOBJ BrushFg = NULL;
1530 GDIBRUSHINST BrushFgInst;
1531 HBRUSH hBrushBg = NULL;
1532 PGDIBRUSHOBJ BrushBg = NULL;
1533 GDIBRUSHINST BrushBgInst;
1534 HBITMAP HSourceGlyph;
1535 SURFOBJ *SourceGlyphSurf;
1536 SIZEL bitSize;
1537 FT_CharMap found = 0, charmap;
1538 INT yoff;
1539 FONTOBJ *FontObj;
1540 PFONTGDI FontGDI;
1541 PTEXTOBJ TextObj;
1542 PPALGDI PalDestGDI;
1543 XLATEOBJ *XlateObj, *XlateObj2;
1544 ULONG Mode;
1545 FT_Render_Mode RenderMode;
1546 BOOLEAN Render;
1547 NTSTATUS Status;
1548 INT *Dx = NULL;
1549 POINT Start;
1550
1551 dc = DC_LockDc(hDC);
1552 if (!dc)
1553 {
1554 SetLastWin32Error(ERROR_INVALID_HANDLE);
1555 return FALSE;
1556 }
1557
1558 if (NULL != UnsafeDx && Count > 0)
1559 {
1560 Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
1561 if (NULL == Dx)
1562 {
1563 goto fail;
1564 }
1565 Status = MmCopyFromCaller(Dx, UnsafeDx, Count * sizeof(INT));
1566 if (! NT_SUCCESS(Status))
1567 {
1568 goto fail;
1569 }
1570 }
1571
1572 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
1573 ASSERT(BitmapObj);
1574 SurfObj = &BitmapObj->SurfObj;
1575
1576 Start.x = XStart; Start.y = YStart;
1577 IntLPtoDP(dc, &Start, 1);
1578
1579 XStart = Start.x + dc->w.DCOrgX;
1580 YStart = Start.y + dc->w.DCOrgY;
1581
1582 /* Create the brushes */
1583 PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
1584 if ( !PalDestGDI )
1585 Mode = PAL_RGB;
1586 else
1587 {
1588 Mode = PalDestGDI->Mode;
1589 PALETTE_UnlockPalette(dc->w.hPalette);
1590 }
1591 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
1592 hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
1593 BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
1594 IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);
1595 if ((fuOptions & ETO_OPAQUE) || dc->w.backgroundMode == OPAQUE)
1596 {
1597 hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor));
1598 if (hBrushBg)
1599 {
1600 BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
1601 IntGdiInitBrushInstance(&BrushBgInst, BrushBg, NULL);
1602 }
1603 else
1604 {
1605 EngDeleteXlate(XlateObj);
1606 goto fail;
1607 }
1608 }
1609 XlateObj2 = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, Mode, NULL, dc->w.hPalette);
1610
1611 SourcePoint.x = 0;
1612 SourcePoint.y = 0;
1613 MaskRect.left = 0;
1614 MaskRect.top = 0;
1615 BrushOrigin.x = 0;
1616 BrushOrigin.y = 0;
1617
1618 if ((fuOptions & ETO_OPAQUE) && lprc)
1619 {
1620 MmCopyFromCaller(&DestRect, lprc, sizeof(RECT));
1621 DestRect.left += dc->w.DCOrgX;
1622 DestRect.top += dc->w.DCOrgY;
1623 DestRect.right += dc->w.DCOrgX;
1624 DestRect.bottom += dc->w.DCOrgY;
1625 IntEngBitBlt(
1626 BitmapObj,
1627 NULL,
1628 NULL,
1629 dc->CombinedClip,
1630 NULL,
1631 &DestRect,
1632 &SourcePoint,
1633 &SourcePoint,
1634 &BrushBgInst.BrushObject,
1635 &BrushOrigin,
1636 PATCOPY);
1637 fuOptions &= ~ETO_OPAQUE;
1638 }
1639 else
1640 {
1641 if (dc->w.backgroundMode == OPAQUE)
1642 {
1643 fuOptions |= ETO_OPAQUE;
1644 }
1645 }
1646
1647 TextObj = TEXTOBJ_LockText(dc->w.hFont);
1648
1649 if (!NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, &FontObj, &FontGDI)))
1650 {
1651 goto fail;
1652 }
1653
1654 face = FontGDI->face;
1655 if (face->charmap == NULL)
1656 {
1657 DPRINT("WARNING: No charmap selected!\n");
1658 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
1659
1660 for (n = 0; n < face->num_charmaps; n++)
1661 {
1662 charmap = face->charmaps[n];
1663 DPRINT("found charmap encoding: %u\n", charmap->encoding);
1664 if (charmap->encoding != 0)
1665 {
1666 found = charmap;
1667 break;
1668 }
1669 }
1670 if (!found)
1671 DPRINT1("WARNING: Could not find desired charmap!\n");
1672 IntLockFreeType;
1673 error = FT_Set_Charmap(face, found);
1674 IntUnLockFreeType;
1675 if (error)
1676 DPRINT1("WARNING: Could not set the charmap!\n");
1677 }
1678
1679 Render = IntIsFontRenderingEnabled();
1680 if (Render)
1681 RenderMode = IntGetFontRenderMode(&TextObj->logfont);
1682 else
1683 RenderMode = FT_RENDER_MODE_MONO;
1684
1685 IntLockFreeType;
1686 error = FT_Set_Pixel_Sizes(
1687 face,
1688 /* FIXME should set character height if neg */
1689 (TextObj->logfont.lfHeight < 0 ?
1690 - TextObj->logfont.lfHeight :
1691 TextObj->logfont.lfHeight),
1692 TextObj->logfont.lfWidth);
1693 IntUnLockFreeType;
1694 if (error)
1695 {
1696 DPRINT1("Error in setting pixel sizes: %u\n", error);
1697 goto fail;
1698 }
1699
1700 /*
1701 * Process the vertical alignment and determine the yoff.
1702 */
1703
1704 if (dc->w.textAlign & TA_BASELINE)
1705 yoff = 0;
1706 else if (dc->w.textAlign & TA_BOTTOM)
1707 yoff = -face->size->metrics.descender >> 6;
1708 else /* TA_TOP */
1709 yoff = face->size->metrics.ascender >> 6;
1710
1711 use_kerning = FT_HAS_KERNING(face);
1712 previous = 0;
1713
1714 /*
1715 * Process the horizontal alignment and modify XStart accordingly.
1716 */
1717
1718 if (dc->w.textAlign & (TA_RIGHT | TA_CENTER))
1719 {
1720 UINT TextWidth = 0;
1721 LPCWSTR TempText = String;
1722 int Start;
1723
1724 /*
1725 * Calculate width of the text.
1726 */
1727
1728 if (NULL != Dx)
1729 {
1730 Start = Count < 2 ? 0 : Count - 2;
1731 TextWidth = Count < 2 ? 0 : Dx[Count - 2];
1732 }
1733 else
1734 {
1735 Start = 0;
1736 }
1737 TempText = String + Start;
1738
1739 for (i = Start; i < Count; i++)
1740 {
1741 IntLockFreeType;
1742 glyph_index = FT_Get_Char_Index(face, *TempText);
1743 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1744 IntUnLockFreeType;
1745
1746 if (error)
1747 {
1748 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1749 }
1750
1751 glyph = face->glyph;
1752
1753 /* retrieve kerning distance */
1754 if (use_kerning && previous && glyph_index)
1755 {
1756 FT_Vector delta;
1757 IntLockFreeType;
1758 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1759 IntUnLockFreeType;
1760 TextWidth += delta.x >> 6;
1761 }
1762
1763 TextWidth += glyph->advance.x >> 6;
1764
1765 previous = glyph_index;
1766 TempText++;
1767 }
1768
1769 previous = 0;
1770
1771 if (dc->w.textAlign & TA_RIGHT)
1772 {
1773 XStart -= TextWidth;
1774 }
1775 else
1776 {
1777 XStart -= TextWidth / 2;
1778 }
1779 }
1780
1781 TextLeft = XStart;
1782 TextTop = YStart;
1783 BackgroundLeft = XStart;
1784
1785 /*
1786 * The main rendering loop.
1787 */
1788
1789 for (i = 0; i < Count; i++)
1790 {
1791 IntLockFreeType;
1792 glyph_index = FT_Get_Char_Index(face, *String);
1793 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1794 IntUnLockFreeType;
1795
1796 if (error)
1797 {
1798 EngDeleteXlate(XlateObj);
1799 EngDeleteXlate(XlateObj2);
1800 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1801 goto fail;
1802 }
1803
1804 glyph = face->glyph;
1805
1806 /* retrieve kerning distance and move pen position */
1807 if (use_kerning && previous && glyph_index && NULL == Dx)
1808 {
1809 FT_Vector delta;
1810 IntLockFreeType;
1811 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1812 IntUnLockFreeType;
1813 TextLeft += delta.x >> 6;
1814 }
1815
1816 if (glyph->format == ft_glyph_format_outline)
1817 {
1818 IntLockFreeType;
1819 error = FT_Render_Glyph(glyph, RenderMode);
1820 IntUnLockFreeType;
1821 if (error)
1822 {
1823 EngDeleteXlate(XlateObj);
1824 EngDeleteXlate(XlateObj2);
1825 DPRINT1("WARNING: Failed to render glyph!\n");
1826 goto fail;
1827 }
1828 pitch = glyph->bitmap.pitch;
1829 } else {
1830 pitch = glyph->bitmap.width;
1831 }
1832
1833 if (fuOptions & ETO_OPAQUE)
1834 {
1835 DestRect.left = BackgroundLeft;
1836 DestRect.right = TextLeft + ((glyph->advance.x + 32) >> 6);
1837 DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6);
1838 DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6);
1839 IntEngBitBlt(
1840 BitmapObj,
1841 NULL,
1842 NULL,
1843 dc->CombinedClip,
1844 NULL,
1845 &DestRect,
1846 &SourcePoint,
1847 &SourcePoint,
1848 &BrushBgInst.BrushObject,
1849 &BrushOrigin,
1850 PATCOPY);
1851 BackgroundLeft = DestRect.right;
1852 }
1853
1854 DestRect.left = TextLeft;
1855 DestRect.right = TextLeft + glyph->bitmap.width;
1856 DestRect.top = TextTop + yoff - glyph->bitmap_top;
1857 DestRect.bottom = DestRect.top + glyph->bitmap.rows;
1858
1859 bitSize.cx = glyph->bitmap.width;
1860 bitSize.cy = glyph->bitmap.rows;
1861 MaskRect.right = glyph->bitmap.width;
1862 MaskRect.bottom = glyph->bitmap.rows;
1863
1864 /*
1865 * We should create the bitmap out of the loop at the biggest possible
1866 * glyph size. Then use memset with 0 to clear it and sourcerect to
1867 * limit the work of the transbitblt.
1868 */
1869
1870 HSourceGlyph = EngCreateBitmap(bitSize, pitch, (glyph->bitmap.pixel_mode == ft_pixel_mode_grays) ? BMF_8BPP : BMF_1BPP, BMF_TOPDOWN, glyph->bitmap.buffer);
1871 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
1872
1873 /*
1874 * Use the font data as a mask to paint onto the DCs surface using a
1875 * brush.
1876 */
1877
1878 IntEngMaskBlt(
1879 SurfObj,
1880 SourceGlyphSurf,
1881 dc->CombinedClip,
1882 XlateObj,
1883 XlateObj2,
1884 &DestRect,
1885 &SourcePoint,
1886 (PPOINTL)&MaskRect,
1887 &BrushFgInst.BrushObject,
1888 &BrushOrigin);
1889
1890 EngUnlockSurface(SourceGlyphSurf);
1891 EngDeleteSurface((HSURF)HSourceGlyph);
1892
1893 if (NULL == Dx)
1894 {
1895 TextLeft += (glyph->advance.x + 32) >> 6;
1896 }
1897 else
1898 {
1899 TextLeft += Dx[i];
1900 }
1901 previous = glyph_index;
1902
1903 String++;
1904 }
1905
1906 EngDeleteXlate(XlateObj);
1907 EngDeleteXlate(XlateObj2);
1908 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
1909 TEXTOBJ_UnlockText(dc->w.hFont);
1910 if (hBrushBg != NULL)
1911 {
1912 BRUSHOBJ_UnlockBrush(hBrushBg);
1913 NtGdiDeleteObject(hBrushBg);
1914 }
1915 BRUSHOBJ_UnlockBrush(hBrushFg);
1916 NtGdiDeleteObject(hBrushFg);
1917 if (NULL != Dx)
1918 {
1919 ExFreePool(Dx);
1920 }
1921 DC_UnlockDc(hDC);
1922
1923 return TRUE;
1924
1925 fail:
1926 TEXTOBJ_UnlockText(dc->w.hFont);
1927 BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
1928 if (hBrushBg != NULL)
1929 {
1930 BRUSHOBJ_UnlockBrush(hBrushBg);
1931 NtGdiDeleteObject(hBrushBg);
1932 }
1933 if (hBrushFg != NULL)
1934 {
1935 BRUSHOBJ_UnlockBrush(hBrushFg);
1936 NtGdiDeleteObject(hBrushFg);
1937 }
1938 if (NULL != Dx)
1939 {
1940 ExFreePool(Dx);
1941 }
1942 DC_UnlockDc(hDC);
1943
1944 return FALSE;
1945 }
1946
1947 BOOL
1948 STDCALL
1949 NtGdiGetAspectRatioFilterEx(HDC hDC,
1950 LPSIZE AspectRatio)
1951 {
1952 UNIMPLEMENTED;
1953 return FALSE;
1954 }
1955
1956 BOOL
1957 STDCALL
1958 NtGdiGetCharABCWidths(HDC hDC,
1959 UINT FirstChar,
1960 UINT LastChar,
1961 LPABC abc)
1962 {
1963 DPRINT1("NtGdiGetCharABCWidths Is unimplemented, keep going anyway\n");
1964 return 1;
1965 }
1966
1967 BOOL
1968 STDCALL
1969 NtGdiGetCharABCWidthsFloat(HDC hDC,
1970 UINT FirstChar,
1971 UINT LastChar,
1972 LPABCFLOAT abcF)
1973 {
1974 UNIMPLEMENTED;
1975 return FALSE;
1976 }
1977
1978 DWORD
1979 STDCALL
1980 NtGdiGetCharacterPlacement(HDC hDC,
1981 LPCWSTR String,
1982 int Count,
1983 int MaxExtent,
1984 LPGCP_RESULTSW Results,
1985 DWORD Flags)
1986 {
1987 UNIMPLEMENTED;
1988 return 0;
1989 }
1990
1991 BOOL
1992 STDCALL
1993 NtGdiGetCharWidth32(HDC hDC,
1994 UINT FirstChar,
1995 UINT LastChar,
1996 LPINT Buffer)
1997 {
1998 LPINT SafeBuffer;
1999 PDC dc;
2000 PTEXTOBJ TextObj;
2001 PFONTGDI FontGDI;
2002 FT_Face face;
2003 FT_CharMap charmap, found = NULL;
2004 UINT i, glyph_index, BufferSize;
2005 HFONT hFont = 0;
2006
2007 if (LastChar < FirstChar)
2008 {
2009 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2010 return FALSE;
2011 }
2012
2013 BufferSize = (LastChar - FirstChar + 1) * sizeof(INT);
2014 SafeBuffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
2015 if (SafeBuffer == NULL)
2016 {
2017 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2018 return FALSE;
2019 }
2020
2021 dc = DC_LockDc(hDC);
2022 if (dc == NULL)
2023 {
2024 ExFreePool(SafeBuffer);
2025 SetLastWin32Error(ERROR_INVALID_HANDLE);
2026 return FALSE;
2027 }
2028 hFont = dc->w.hFont;
2029 TextObj = TEXTOBJ_LockText(hFont);
2030 DC_UnlockDc(hDC);
2031
2032 if (TextObj == NULL)
2033 {
2034 ExFreePool(SafeBuffer);
2035 SetLastWin32Error(ERROR_INVALID_HANDLE);
2036 return FALSE;
2037 }
2038
2039 if (!NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI)))
2040 {
2041 ExFreePool(SafeBuffer);
2042 SetLastWin32Error(ERROR_INVALID_HANDLE);
2043 TEXTOBJ_UnlockText(hFont);
2044 return FALSE;
2045 }
2046
2047 face = FontGDI->face;
2048 if (face->charmap == NULL)
2049 {
2050 for (i = 0; i < face->num_charmaps; i++)
2051 {
2052 charmap = face->charmaps[i];
2053 if (charmap->encoding != 0)
2054 {
2055 found = charmap;
2056 break;
2057 }
2058 }
2059
2060 if (!found)
2061 {
2062 DPRINT1("WARNING: Could not find desired charmap!\n");
2063 ExFreePool(SafeBuffer);
2064 SetLastWin32Error(ERROR_INVALID_HANDLE);
2065 return FALSE;
2066 }
2067
2068 IntLockFreeType;
2069 FT_Set_Charmap(face, found);
2070 IntUnLockFreeType;
2071 }
2072
2073 IntLockFreeType;
2074 FT_Set_Pixel_Sizes(face,
2075 /* FIXME should set character height if neg */
2076 (TextObj->logfont.lfHeight < 0 ?
2077 - TextObj->logfont.lfHeight :
2078 TextObj->logfont.lfHeight),
2079 TextObj->logfont.lfWidth);
2080
2081 for (i = FirstChar; i <= LastChar; i++)
2082 {
2083 glyph_index = FT_Get_Char_Index(face, i);
2084 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2085 SafeBuffer[i - FirstChar] = face->glyph->advance.x >> 6;
2086 }
2087 IntUnLockFreeType;
2088 TEXTOBJ_UnlockText(hFont);
2089 MmCopyToCaller(Buffer, SafeBuffer, BufferSize);
2090 ExFreePool(SafeBuffer);
2091 return TRUE;
2092 }
2093
2094 BOOL
2095 STDCALL
2096 NtGdiGetCharWidthFloat(HDC hDC,
2097 UINT FirstChar,
2098 UINT LastChar,
2099 PFLOAT Buffer)
2100 {
2101 UNIMPLEMENTED;
2102 return FALSE;
2103 }
2104
2105 DWORD
2106 STDCALL
2107 NtGdiGetFontLanguageInfo(HDC hDC)
2108 {
2109 UNIMPLEMENTED;
2110 return 0;
2111 }
2112
2113 DWORD
2114 STDCALL
2115 NtGdiGetGlyphOutline(HDC hDC,
2116 UINT Char,
2117 UINT Format,
2118 LPGLYPHMETRICS gm,
2119 DWORD Bufsize,
2120 LPVOID Buffer,
2121 CONST LPMAT2 mat2)
2122 {
2123 UNIMPLEMENTED;
2124 return 0;
2125 }
2126
2127 DWORD
2128 STDCALL
2129 NtGdiGetKerningPairs(HDC hDC,
2130 DWORD NumPairs,
2131 LPKERNINGPAIR krnpair)
2132 {
2133 UNIMPLEMENTED;
2134 return 0;
2135 }
2136
2137 UINT
2138 STDCALL
2139 NtGdiGetOutlineTextMetrics(HDC hDC,
2140 UINT Data,
2141 LPOUTLINETEXTMETRICW otm)
2142 {
2143 UNIMPLEMENTED;
2144 return 0;
2145 }
2146
2147 BOOL
2148 STDCALL
2149 NtGdiGetRasterizerCaps(LPRASTERIZER_STATUS rs,
2150 UINT Size)
2151 {
2152 UNIMPLEMENTED;
2153 return FALSE;
2154 }
2155
2156 UINT
2157 STDCALL
2158 NtGdiGetTextCharset(HDC hDC)
2159 {
2160 UNIMPLEMENTED;
2161 return 0;
2162 }
2163
2164 UINT
2165 STDCALL
2166 NtGdiGetTextCharsetInfo(HDC hDC,
2167 LPFONTSIGNATURE Sig,
2168 DWORD Flags)
2169 {
2170 UNIMPLEMENTED;
2171 return 0;
2172 }
2173
2174 static BOOL
2175 FASTCALL
2176 TextIntGetTextExtentPoint(HDC hDC,
2177 PTEXTOBJ TextObj,
2178 LPCWSTR String,
2179 int Count,
2180 int MaxExtent,
2181 LPINT Fit,
2182 LPINT Dx,
2183 LPSIZE Size)
2184 {
2185 PFONTGDI FontGDI;
2186 FT_Face face;
2187 FT_GlyphSlot glyph;
2188 INT error, n, glyph_index, i, previous;
2189 LONG TotalWidth = 0;
2190 FT_CharMap charmap, found = NULL;
2191 BOOL use_kerning;
2192
2193 if (!NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI)))
2194 {
2195 return FALSE;
2196 }
2197
2198 face = FontGDI->face;
2199 if (NULL != Fit)
2200 {
2201 *Fit = 0;
2202 }
2203
2204 if (face->charmap == NULL)
2205 {
2206 DPRINT("WARNING: No charmap selected!\n");
2207 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
2208
2209 for (n = 0; n < face->num_charmaps; n++)
2210 {
2211 charmap = face->charmaps[n];
2212 DPRINT("found charmap encoding: %u\n", charmap->encoding);
2213 if (charmap->encoding != 0)
2214 {
2215 found = charmap;
2216 break;
2217 }
2218 }
2219
2220 if (! found)
2221 {
2222 DPRINT1("WARNING: Could not find desired charmap!\n");
2223 }
2224
2225 IntLockFreeType;
2226 error = FT_Set_Charmap(face, found);
2227 IntUnLockFreeType;
2228 if (error)
2229 {
2230 DPRINT1("WARNING: Could not set the charmap!\n");
2231 }
2232 }
2233
2234 IntLockFreeType;
2235 error = FT_Set_Pixel_Sizes(face,
2236 /* FIXME should set character height if neg */
2237 (TextObj->logfont.lfHeight < 0 ?
2238 - TextObj->logfont.lfHeight :
2239 TextObj->logfont.lfHeight),
2240 TextObj->logfont.lfWidth);
2241 IntUnLockFreeType;
2242 if (error)
2243 {
2244 DPRINT1("Error in setting pixel sizes: %u\n", error);
2245 }
2246
2247 use_kerning = FT_HAS_KERNING(face);
2248 previous = 0;
2249
2250 for (i = 0; i < Count; i++)
2251 {
2252 IntLockFreeType;
2253 glyph_index = FT_Get_Char_Index(face, *String);
2254 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2255 IntUnLockFreeType;
2256 if (error)
2257 {
2258 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
2259 }
2260 glyph = face->glyph;
2261
2262 /* retrieve kerning distance */
2263 if (use_kerning && previous && glyph_index)
2264 {
2265 FT_Vector delta;
2266 IntLockFreeType;
2267 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
2268 IntUnLockFreeType;
2269 TotalWidth += delta.x >> 6;
2270 }
2271
2272 TotalWidth += glyph->advance.x >> 6;
2273
2274 if (TotalWidth <= MaxExtent && NULL != Fit)
2275 {
2276 *Fit = i + 1;
2277 }
2278 if (NULL != Dx)
2279 {
2280 Dx[i] = TotalWidth;
2281 }
2282
2283 previous = glyph_index;
2284 String++;
2285 }
2286
2287 Size->cx = TotalWidth;
2288 Size->cy = (TextObj->logfont.lfHeight < 0 ? - TextObj->logfont.lfHeight : TextObj->logfont.lfHeight);
2289 Size->cy = EngMulDiv(Size->cy, NtGdiGetDeviceCaps(hDC, LOGPIXELSY), 72);
2290
2291 return TRUE;
2292 }
2293
2294 BOOL
2295 STDCALL
2296 NtGdiGetTextExtentExPoint(HDC hDC,
2297 LPCWSTR UnsafeString,
2298 int Count,
2299 int MaxExtent,
2300 LPINT UnsafeFit,
2301 LPINT UnsafeDx,
2302 LPSIZE UnsafeSize)
2303 {
2304 PDC dc;
2305 LPWSTR String;
2306 SIZE Size;
2307 NTSTATUS Status;
2308 BOOLEAN Result;
2309 INT Fit;
2310 LPINT Dx;
2311 PTEXTOBJ TextObj;
2312
2313 if (Count < 0)
2314 {
2315 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2316 return FALSE;
2317 }
2318 if (0 == Count)
2319 {
2320 Size.cx = 0;
2321 Size.cy = 0;
2322 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
2323 if (! NT_SUCCESS(Status))
2324 {
2325 SetLastNtError(Status);
2326 return FALSE;
2327 }
2328 return TRUE;
2329 }
2330
2331 String = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), TAG_GDITEXT);
2332 if (NULL == String)
2333 {
2334 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2335 return FALSE;
2336 }
2337
2338 if (NULL != UnsafeDx)
2339 {
2340 Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
2341 if (NULL == Dx)
2342 {
2343 ExFreePool(String);
2344 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2345 return FALSE;
2346 }
2347 }
2348 else
2349 {
2350 Dx = NULL;
2351 }
2352
2353 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
2354 if (! NT_SUCCESS(Status))
2355 {
2356 if (NULL != Dx)
2357 {
2358 ExFreePool(Dx);
2359 }
2360 ExFreePool(String);
2361 SetLastNtError(Status);
2362 return FALSE;
2363 }
2364
2365 dc = DC_LockDc(hDC);
2366 if (NULL == dc)
2367 {
2368 if (NULL != Dx)
2369 {
2370 ExFreePool(Dx);
2371 }
2372 ExFreePool(String);
2373 SetLastWin32Error(ERROR_INVALID_HANDLE);
2374 return FALSE;
2375 }
2376 TextObj = TEXTOBJ_LockText(dc->w.hFont);
2377 DC_UnlockDc(hDC);
2378 Result = TextIntGetTextExtentPoint(hDC, TextObj, String, Count, MaxExtent,
2379 NULL == UnsafeFit ? NULL : &Fit, Dx, &Size);
2380 TEXTOBJ_UnlockText(dc->w.hFont);
2381
2382 ExFreePool(String);
2383 if (! Result)
2384 {
2385 if (NULL != Dx)
2386 {
2387 ExFreePool(Dx);
2388 }
2389 return FALSE;
2390 }
2391
2392 if (NULL != UnsafeFit)
2393 {
2394 Status = MmCopyToCaller(UnsafeFit, &Fit, sizeof(INT));
2395 if (! NT_SUCCESS(Status))
2396 {
2397 if (NULL != Dx)
2398 {
2399 ExFreePool(Dx);
2400 }
2401 SetLastNtError(Status);
2402 return FALSE;
2403 }
2404 }
2405
2406 if (NULL != UnsafeDx)
2407 {
2408 Status = MmCopyToCaller(UnsafeDx, Dx, Count * sizeof(INT));
2409 if (! NT_SUCCESS(Status))
2410 {
2411 if (NULL != Dx)
2412 {
2413 ExFreePool(Dx);
2414 }
2415 SetLastNtError(Status);
2416 return FALSE;
2417 }
2418 }
2419 if (NULL != Dx)
2420 {
2421 ExFreePool(Dx);
2422 }
2423
2424 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
2425 if (! NT_SUCCESS(Status))
2426 {
2427 SetLastNtError(Status);
2428 return FALSE;
2429 }
2430
2431 return TRUE;
2432 }
2433
2434 BOOL
2435 STDCALL
2436 NtGdiGetTextExtentPoint(HDC hDC,
2437 LPCWSTR String,
2438 int Count,
2439 LPSIZE Size)
2440 {
2441 return NtGdiGetTextExtentExPoint(hDC, String, Count, 0, NULL, NULL, Size);
2442 }
2443
2444 BOOL
2445 STDCALL
2446 NtGdiGetTextExtentPoint32(HDC hDC,
2447 LPCWSTR UnsafeString,
2448 int Count,
2449 LPSIZE UnsafeSize)
2450 {
2451 PDC dc;
2452 LPWSTR String;
2453 SIZE Size;
2454 NTSTATUS Status;
2455 BOOLEAN Result;
2456 PTEXTOBJ TextObj;
2457
2458 if (Count < 0)
2459 {
2460 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2461 return FALSE;
2462 }
2463 if (0 == Count)
2464 {
2465 Size.cx = 0;
2466 Size.cy = 0;
2467 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
2468 if (! NT_SUCCESS(Status))
2469 {
2470 SetLastNtError(Status);
2471 return FALSE;
2472 }
2473 return TRUE;
2474 }
2475
2476 String = ExAllocatePool(PagedPool, Count * sizeof(WCHAR));
2477 if (NULL == String)
2478 {
2479 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2480 return FALSE;
2481 }
2482
2483 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
2484 if (! NT_SUCCESS(Status))
2485 {
2486 ExFreePool(String);
2487 SetLastNtError(Status);
2488 return FALSE;
2489 }
2490
2491 dc = DC_LockDc(hDC);
2492 if (NULL == dc)
2493 {
2494 ExFreePool(String);
2495 SetLastWin32Error(ERROR_INVALID_HANDLE);
2496 return FALSE;
2497 }
2498 TextObj = TEXTOBJ_LockText(dc->w.hFont);
2499 DC_UnlockDc(hDC);
2500 Result = TextIntGetTextExtentPoint (
2501 hDC, TextObj, String, Count, 0, NULL, NULL, &Size);
2502 dc = DC_LockDc(hDC);
2503 ASSERT(dc); // it succeeded earlier, it should now, too
2504 TEXTOBJ_UnlockText(dc->w.hFont);
2505 DC_UnlockDc(hDC);
2506
2507 ExFreePool(String);
2508 if (! Result)
2509 {
2510 return FALSE;
2511 }
2512
2513 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
2514 if (! NT_SUCCESS(Status))
2515 {
2516 SetLastNtError(Status);
2517 return FALSE;
2518 }
2519
2520 return TRUE;
2521 }
2522
2523 INT STDCALL
2524 NtGdiGetTextFace(HDC hDC, INT Count, LPWSTR FaceName)
2525 {
2526 PDC Dc;
2527 PTEXTOBJ TextObj;
2528 NTSTATUS Status;
2529
2530 Dc = DC_LockDc(hDC);
2531 if (Dc == NULL)
2532 {
2533 SetLastWin32Error(ERROR_INVALID_HANDLE);
2534 return FALSE;
2535 }
2536 TextObj = TEXTOBJ_LockText(Dc->w.hFont);
2537 DC_UnlockDc(hDC);
2538
2539 Count = min(Count, wcslen(TextObj->logfont.lfFaceName));
2540 Status = MmCopyToCaller(FaceName, TextObj->logfont.lfFaceName, Count * sizeof(WCHAR));
2541 if (!NT_SUCCESS(Status))
2542 {
2543 SetLastNtError(Status);
2544 return 0;
2545 }
2546
2547 return Count;
2548 }
2549
2550 BOOL
2551 STDCALL
2552 NtGdiGetTextMetrics(HDC hDC,
2553 LPTEXTMETRICW tm)
2554 {
2555 PDC dc;
2556 PTEXTOBJ TextObj;
2557 PFONTGDI FontGDI;
2558 NTSTATUS Status = STATUS_SUCCESS;
2559 TEXTMETRICW SafeTm;
2560 FT_Face Face;
2561 TT_OS2 *pOS2;
2562 ULONG Error;
2563
2564 if (NULL == tm)
2565 {
2566 SetLastWin32Error(STATUS_INVALID_PARAMETER);
2567 return FALSE;
2568 }
2569
2570 if(!(dc = DC_LockDc(hDC)))
2571 {
2572 SetLastWin32Error(ERROR_INVALID_HANDLE);
2573 return FALSE;
2574 }
2575
2576 TextObj = TEXTOBJ_LockText(dc->w.hFont);
2577 if (NULL != TextObj)
2578 {
2579 Status = GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI);
2580 if (NT_SUCCESS(Status))
2581 {
2582 Face = FontGDI->face;
2583 IntLockFreeType;
2584 Error = FT_Set_Pixel_Sizes(Face,
2585 /* FIXME should set character height if neg */
2586 (TextObj->logfont.lfHeight < 0 ?
2587 - TextObj->logfont.lfHeight :
2588 TextObj->logfont.lfHeight),
2589 TextObj->logfont.lfWidth);
2590 IntUnLockFreeType;
2591 if (0 != Error)
2592 {
2593 DPRINT1("Error in setting pixel sizes: %u\n", Error);
2594 Status = STATUS_UNSUCCESSFUL;
2595 }
2596 else
2597 {
2598 memcpy(&SafeTm, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
2599 IntLockFreeType;
2600 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
2601 IntUnLockFreeType;
2602 if (NULL == pOS2)
2603 {
2604 DPRINT1("Can't find OS/2 table - not TT font?\n");
2605 Status = STATUS_UNSUCCESSFUL;
2606 }
2607 else
2608 {
2609 SafeTm.tmAveCharWidth = (pOS2->xAvgCharWidth + 32) >> 6;
2610 }
2611 SafeTm.tmAscent = (Face->size->metrics.ascender + 32) >> 6; // units above baseline
2612 SafeTm.tmDescent = (32 - Face->size->metrics.descender) >> 6; // units below baseline
2613 SafeTm.tmHeight = SafeTm.tmAscent + SafeTm.tmDescent;
2614 SafeTm.tmMaxCharWidth = (Face->size->metrics.max_advance + 32) >> 6;
2615 if (FT_IS_SFNT(FontGDI->face))
2616 {
2617 SafeTm.tmPitchAndFamily |= TMPF_TRUETYPE;
2618 }
2619 Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
2620 }
2621 }
2622 TEXTOBJ_UnlockText(dc->w.hFont);
2623 }
2624 else
2625 {
2626 ASSERT(FALSE);
2627 Status = STATUS_INVALID_HANDLE;
2628 }
2629 DC_UnlockDc(hDC);
2630
2631 if(!NT_SUCCESS(Status))
2632 {
2633 SetLastNtError(Status);
2634 return FALSE;
2635 }
2636
2637 return TRUE;
2638 }
2639
2640 BOOL
2641 STDCALL
2642 NtGdiPolyTextOut(HDC hDC,
2643 CONST LPPOLYTEXTW txt,
2644 int Count)
2645 {
2646 UNIMPLEMENTED;
2647 return FALSE;
2648 }
2649
2650 BOOL
2651 STDCALL
2652 NtGdiRemoveFontResource(LPCWSTR FileName)
2653 {
2654 UNIMPLEMENTED;
2655 return FALSE;
2656 }
2657
2658 DWORD
2659 STDCALL
2660 NtGdiSetMapperFlags(HDC hDC,
2661 DWORD Flag)
2662 {
2663 UNIMPLEMENTED;
2664 return 0;
2665 }
2666
2667 UINT
2668 STDCALL
2669 NtGdiSetTextAlign(HDC hDC,
2670 UINT Mode)
2671 {
2672 UINT prevAlign;
2673 DC *dc;
2674
2675 dc = DC_LockDc(hDC);
2676 if (!dc)
2677 {
2678 SetLastWin32Error(ERROR_INVALID_HANDLE);
2679 return GDI_ERROR;
2680 }
2681 prevAlign = dc->w.textAlign;
2682 dc->w.textAlign = Mode;
2683 DC_UnlockDc( hDC );
2684 return prevAlign;
2685 }
2686
2687 COLORREF
2688 STDCALL
2689 NtGdiSetTextColor(HDC hDC,
2690 COLORREF color)
2691 {
2692 COLORREF oldColor;
2693 PDC dc = DC_LockDc(hDC);
2694 HBRUSH hBrush;
2695
2696 if (!dc)
2697 {
2698 SetLastWin32Error(ERROR_INVALID_HANDLE);
2699 return CLR_INVALID;
2700 }
2701
2702 oldColor = dc->w.textColor;
2703 dc->w.textColor = color;
2704 hBrush = dc->w.hBrush;
2705 DC_UnlockDc( hDC );
2706 NtGdiSelectObject(hDC, hBrush);
2707 return oldColor;
2708 }
2709
2710 BOOL
2711 STDCALL
2712 NtGdiSetTextJustification(HDC hDC,
2713 int BreakExtra,
2714 int BreakCount)
2715 {
2716 UNIMPLEMENTED;
2717 return FALSE;
2718 }
2719
2720 BOOL STDCALL
2721 NtGdiTextOut(
2722 HDC hDC,
2723 INT XStart,
2724 INT YStart,
2725 LPCWSTR String,
2726 INT Count)
2727 {
2728 return NtGdiExtTextOut(hDC, XStart, YStart, 0, NULL, String, Count, NULL);
2729 }
2730
2731 DWORD STDCALL
2732 NtGdiGetFontData(
2733 HDC hDC,
2734 DWORD Table,
2735 DWORD Offset,
2736 LPVOID Buffer,
2737 DWORD Size)
2738 {
2739 PDC Dc;
2740 HFONT hFont;
2741 PTEXTOBJ TextObj;
2742 PFONTGDI FontGdi;
2743 DWORD Result = GDI_ERROR;
2744 NTSTATUS Status;
2745
2746 Dc = DC_LockDc(hDC);
2747 if (Dc == NULL)
2748 {
2749 SetLastWin32Error(ERROR_INVALID_HANDLE);
2750 return GDI_ERROR;
2751 }
2752 hFont = Dc->w.hFont;
2753 TextObj = TEXTOBJ_LockText(hFont);
2754 DC_UnlockDc(hDC);
2755
2756 if (TextObj == NULL)
2757 {
2758 SetLastWin32Error(ERROR_INVALID_HANDLE);
2759 return GDI_ERROR;
2760 }
2761
2762 Status = GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGdi);
2763 if (NT_SUCCESS(Status))
2764 {
2765 IntLockFreeType;
2766
2767 if (FT_IS_SFNT(FontGdi->face))
2768 {
2769 if (Table)
2770 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
2771 (Table << 8 & 0xFF0000);
2772
2773 if (Buffer == NULL)
2774 Size = 0;
2775
2776 if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
2777 Result = Size;
2778 }
2779
2780 IntUnLockFreeType;
2781 }
2782
2783 TEXTOBJ_UnlockText(hFont);
2784
2785 return Result;
2786 }
2787
2788 static UINT FASTCALL
2789 GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
2790 {
2791 ANSI_STRING EntryFaceNameA;
2792 UNICODE_STRING EntryFaceNameW;
2793 unsigned Size;
2794 OUTLINETEXTMETRICW *Otm;
2795 LONG WeightDiff;
2796 NTSTATUS Status;
2797 UINT Score = 1;
2798
2799 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
2800 Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
2801 if (NT_SUCCESS(Status))
2802 {
2803 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
2804 {
2805 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
2806 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
2807 }
2808 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
2809 {
2810 Score += 49;
2811 }
2812 RtlFreeUnicodeString(&EntryFaceNameW);
2813 }
2814
2815 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2816 Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
2817 if (NULL == Otm)
2818 {
2819 return Score;
2820 }
2821 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
2822
2823 if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
2824 (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
2825 {
2826 Score += 25;
2827 }
2828 if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
2829 {
2830 WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
2831 }
2832 else
2833 {
2834 WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
2835 }
2836 Score += (1000 - WeightDiff) / (1000 / 25);
2837
2838 ExFreePool(Otm);
2839
2840 return Score;
2841 }
2842
2843 static VOID FASTCALL
2844 FindBestFontFromList(HFONT *Font, UINT *MatchScore, LOGFONTW *LogFont,
2845 PUNICODE_STRING FaceName, PLIST_ENTRY Head)
2846 {
2847 PLIST_ENTRY Entry;
2848 PFONT_ENTRY CurrentEntry;
2849 PFONTGDI FontGDI;
2850 UINT Score;
2851
2852 Entry = Head->Flink;
2853 while (Entry != Head)
2854 {
2855 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
2856 if (NULL == (FontGDI = AccessInternalObject((ULONG) CurrentEntry->hFont)))
2857 {
2858 Entry = Entry->Flink;
2859 continue;
2860 }
2861 Score = GetFontScore(LogFont, FaceName, FontGDI);
2862 if (*MatchScore < Score)
2863 {
2864 *Font = CurrentEntry->hFont;
2865 *MatchScore = Score;
2866 }
2867 Entry = Entry->Flink;
2868 }
2869 }
2870
2871 static BOOLEAN FASTCALL
2872 SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
2873 LPCWSTR Key)
2874 {
2875 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
2876 NTSTATUS Status;
2877 UNICODE_STRING Value;
2878
2879 RtlInitUnicodeString(&Value, NULL);
2880
2881 QueryTable[0].QueryRoutine = NULL;
2882 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
2883 RTL_QUERY_REGISTRY_REQUIRED;
2884 QueryTable[0].Name = FaceName->Buffer;
2885 QueryTable[0].EntryContext = &Value;
2886 QueryTable[0].DefaultType = REG_NONE;
2887 QueryTable[0].DefaultData = NULL;
2888 QueryTable[0].DefaultLength = 0;
2889
2890 QueryTable[1].QueryRoutine = NULL;
2891 QueryTable[1].Name = NULL;
2892
2893 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
2894 Key,
2895 QueryTable,
2896 NULL,
2897 NULL);
2898 if (NT_SUCCESS(Status))
2899 {
2900 RtlFreeUnicodeString(FaceName);
2901 *FaceName = Value;
2902 }
2903
2904 return NT_SUCCESS(Status);
2905 }
2906
2907 static void FASTCALL
2908 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
2909 {
2910 if (10 < Level) /* Enough is enough */
2911 {
2912 return;
2913 }
2914
2915 if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
2916 SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
2917 {
2918 SubstituteFontFamily(FaceName, Level + 1);
2919 }
2920 }
2921
2922 NTSTATUS FASTCALL
2923 TextIntRealizeFont(HFONT FontHandle)
2924 {
2925 NTSTATUS Status = STATUS_SUCCESS;
2926 PTEXTOBJ TextObj;
2927 UNICODE_STRING FaceName;
2928 PW32PROCESS Win32Process;
2929 UINT MatchScore;
2930
2931 TextObj = TEXTOBJ_LockText(FontHandle);
2932 if (NULL == TextObj)
2933 {
2934 return STATUS_INVALID_HANDLE;
2935 }
2936
2937 if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.lfFaceName))
2938 {
2939 TEXTOBJ_UnlockText(FontHandle);
2940 return STATUS_NO_MEMORY;
2941 }
2942 SubstituteFontFamily(&FaceName, 0);
2943 MatchScore = 0;
2944 TextObj->GDIFontHandle = NULL;
2945
2946 /* First search private fonts */
2947 Win32Process = PsGetWin32Process();
2948 IntLockProcessPrivateFonts(Win32Process);
2949 FindBestFontFromList(&TextObj->GDIFontHandle, &MatchScore,
2950 &TextObj->logfont, &FaceName,
2951 &Win32Process->PrivateFontListHead);
2952 IntUnLockProcessPrivateFonts(Win32Process);
2953
2954 /* Search system fonts */
2955 IntLockGlobalFonts;
2956 FindBestFontFromList(&TextObj->GDIFontHandle, &MatchScore,
2957 &TextObj->logfont, &FaceName,
2958 &FontListHead);
2959 IntUnLockGlobalFonts;
2960
2961 if (NULL == TextObj->GDIFontHandle)
2962 {
2963 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
2964 TextObj->logfont.lfFaceName);
2965 Status = STATUS_NOT_FOUND;
2966 }
2967
2968 RtlFreeUnicodeString(&FaceName);
2969 TEXTOBJ_UnlockText(FontHandle);
2970
2971 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->GDIFontHandle)) != 0);
2972
2973 return Status;
2974 }
2975
2976 INT FASTCALL
2977 FontGetObject(PTEXTOBJ Font, INT Count, PVOID Buffer)
2978 {
2979 if (Count < sizeof(LOGFONTW))
2980 {
2981 SetLastWin32Error(ERROR_BUFFER_OVERFLOW);
2982 return 0;
2983 }
2984
2985 RtlCopyMemory(Buffer, &Font->logfont, sizeof(LOGFONTW));
2986
2987 return sizeof(LOGFONTW);
2988 }
2989
2990 /* EOF */