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