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