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