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