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