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