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