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