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