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