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