f3452874985120a56a3c41a96de2453a066f5c2d
[reactos.git] / reactos / subsystems / win32 / 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 FT_GLYPH_H
32 #include <freetype/tttables.h>
33 #include <freetype/fttrigon.h>
34 #include <freetype/ftglyph.h>
35 #include <freetype/ftoutln.h>
36 #include <freetype/ftwinfnt.h>
37
38 #define NDEBUG
39 #include <debug.h>
40
41 FT_Library library;
42
43 typedef struct _FONT_ENTRY {
44 LIST_ENTRY ListEntry;
45 FONTGDI *Font;
46 UNICODE_STRING FaceName;
47 BYTE NotEnum;
48 } FONT_ENTRY, *PFONT_ENTRY;
49
50 /* The FreeType library is not thread safe, so we have
51 to serialize access to it */
52 static FAST_MUTEX FreeTypeLock;
53
54 static LIST_ENTRY FontListHead;
55 static FAST_MUTEX FontListLock;
56 static BOOL RenderingEnabled = TRUE;
57
58 #define MAX_FONT_CACHE 256
59 UINT Hits;
60 UINT Misses;
61
62 typedef struct _FONT_CACHE_ENTRY {
63 LIST_ENTRY ListEntry;
64 int GlyphIndex;
65 FT_Face Face;
66 FT_Glyph Glyph;
67 int Height;
68 } FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY;
69 static LIST_ENTRY FontCacheListHead;
70 static UINT FontCacheNumEntries;
71
72 static PWCHAR ElfScripts[32] = { /* these are in the order of the fsCsb[0] bits */
73 L"Western", /*00*/
74 L"Central_European",
75 L"Cyrillic",
76 L"Greek",
77 L"Turkish",
78 L"Hebrew",
79 L"Arabic",
80 L"Baltic",
81 L"Vietnamese", /*08*/
82 NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/
83 L"Thai",
84 L"Japanese",
85 L"CHINESE_GB2312",
86 L"Hangul",
87 L"CHINESE_BIG5",
88 L"Hangul(Johab)",
89 NULL, NULL, /*23*/
90 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
91 L"Symbol" /*31*/
92 };
93
94 /*
95 * For NtGdiTranslateCharsetInfo
96 */
97 #define FS(x) {{0,0,0,0},{0x1<<(x),0}}
98 #define MAXTCIINDEX 32
99 static CHARSETINFO FontTci[MAXTCIINDEX] = {
100 /* ANSI */
101 { ANSI_CHARSET, 1252, FS(0)},
102 { EASTEUROPE_CHARSET, 1250, FS(1)},
103 { RUSSIAN_CHARSET, 1251, FS(2)},
104 { GREEK_CHARSET, 1253, FS(3)},
105 { TURKISH_CHARSET, 1254, FS(4)},
106 { HEBREW_CHARSET, 1255, FS(5)},
107 { ARABIC_CHARSET, 1256, FS(6)},
108 { BALTIC_CHARSET, 1257, FS(7)},
109 { VIETNAMESE_CHARSET, 1258, FS(8)},
110 /* reserved by ANSI */
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 { DEFAULT_CHARSET, 0, FS(0)},
116 { DEFAULT_CHARSET, 0, FS(0)},
117 { DEFAULT_CHARSET, 0, FS(0)},
118 /* ANSI and OEM */
119 { THAI_CHARSET, 874, FS(16)},
120 { SHIFTJIS_CHARSET, 932, FS(17)},
121 { GB2312_CHARSET, 936, FS(18)},
122 { HANGEUL_CHARSET, 949, FS(19)},
123 { CHINESEBIG5_CHARSET, 950, FS(20)},
124 { JOHAB_CHARSET, 1361, FS(21)},
125 /* reserved for alternate ANSI and OEM */
126 { DEFAULT_CHARSET, 0, FS(0)},
127 { DEFAULT_CHARSET, 0, FS(0)},
128 { DEFAULT_CHARSET, 0, FS(0)},
129 { DEFAULT_CHARSET, 0, FS(0)},
130 { DEFAULT_CHARSET, 0, FS(0)},
131 { DEFAULT_CHARSET, 0, FS(0)},
132 { DEFAULT_CHARSET, 0, FS(0)},
133 { DEFAULT_CHARSET, 0, FS(0)},
134 /* reserved for system */
135 { DEFAULT_CHARSET, 0, FS(0)},
136 { SYMBOL_CHARSET, 42 /* CP_SYMBOL */, FS(31)},
137 };
138
139 VOID FASTCALL
140 IntLoadSystemFonts(VOID);
141
142 INT FASTCALL
143 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics);
144
145 BOOL FASTCALL
146 InitFontSupport(VOID)
147 {
148 ULONG ulError;
149
150 InitializeListHead(&FontListHead);
151 InitializeListHead(&FontCacheListHead);
152 FontCacheNumEntries = 0;
153 ExInitializeFastMutex(&FontListLock);
154 ExInitializeFastMutex(&FreeTypeLock);
155
156 ulError = FT_Init_FreeType(&library);
157 if (ulError) {
158 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
159 return FALSE;
160 }
161
162 IntLoadSystemFonts();
163
164 return TRUE;
165 }
166
167 /*
168 * IntLoadSystemFonts
169 *
170 * Search the system font directory and adds each font found.
171 */
172
173 VOID FASTCALL
174 IntLoadSystemFonts(VOID)
175 {
176 OBJECT_ATTRIBUTES ObjectAttributes;
177 UNICODE_STRING Directory, SearchPattern, FileName, TempString;
178 IO_STATUS_BLOCK Iosb;
179 HANDLE hDirectory;
180 BYTE *DirInfoBuffer;
181 PFILE_DIRECTORY_INFORMATION DirInfo;
182 BOOL bRestartScan = TRUE;
183 NTSTATUS Status;
184
185 RtlInitUnicodeString(&Directory, L"\\SystemRoot\\media\\fonts\\");
186 /* FIXME: Add support for other font types */
187 RtlInitUnicodeString(&SearchPattern, L"*.ttf");
188
189 InitializeObjectAttributes(
190 &ObjectAttributes,
191 &Directory,
192 OBJ_CASE_INSENSITIVE,
193 NULL,
194 NULL);
195
196 Status = ZwOpenFile(
197 &hDirectory,
198 SYNCHRONIZE | FILE_LIST_DIRECTORY,
199 &ObjectAttributes,
200 &Iosb,
201 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
202 FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
203
204 if (NT_SUCCESS(Status))
205 {
206 DirInfoBuffer = ExAllocatePool(PagedPool, 0x4000);
207 if (DirInfoBuffer == NULL)
208 {
209 ZwClose(hDirectory);
210 return;
211 }
212
213 FileName.Buffer = ExAllocatePool(PagedPool, MAX_PATH * sizeof(WCHAR));
214 if (FileName.Buffer == NULL)
215 {
216 ExFreePool(DirInfoBuffer);
217 ZwClose(hDirectory);
218 return;
219 }
220 FileName.Length = 0;
221 FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
222
223 while (1)
224 {
225 Status = ZwQueryDirectoryFile(
226 hDirectory,
227 NULL,
228 NULL,
229 NULL,
230 &Iosb,
231 DirInfoBuffer,
232 0x4000,
233 FileDirectoryInformation,
234 FALSE,
235 &SearchPattern,
236 bRestartScan);
237
238 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
239 {
240 break;
241 }
242
243 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
244 while (1)
245 {
246 TempString.Buffer = DirInfo->FileName;
247 TempString.Length =
248 TempString.MaximumLength = DirInfo->FileNameLength;
249 RtlCopyUnicodeString(&FileName, &Directory);
250 RtlAppendUnicodeStringToString(&FileName, &TempString);
251 IntGdiAddFontResource(&FileName, 0);
252 if (DirInfo->NextEntryOffset == 0)
253 break;
254 DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
255 }
256
257 bRestartScan = FALSE;
258 }
259
260 ExFreePool(FileName.Buffer);
261 ExFreePool(DirInfoBuffer);
262 ZwClose(hDirectory);
263 }
264 }
265
266 /*
267 * IntGdiAddFontResource
268 *
269 * Adds the font resource from the specified file to the system.
270 */
271
272 INT FASTCALL
273 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
274 {
275 FONTGDI *FontGDI;
276 NTSTATUS Status;
277 HANDLE FileHandle;
278 OBJECT_ATTRIBUTES ObjectAttributes;
279 PVOID Buffer = NULL;
280 IO_STATUS_BLOCK Iosb;
281 INT Error;
282 FT_Face Face;
283 ANSI_STRING AnsiFaceName;
284 PFONT_ENTRY Entry;
285 PSECTION_OBJECT SectionObject;
286 ULONG ViewSize = 0;
287
288 /* Open the font file */
289
290 InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
291 Status = ZwOpenFile(
292 &FileHandle,
293 FILE_GENERIC_READ | SYNCHRONIZE,
294 &ObjectAttributes,
295 &Iosb,
296 FILE_SHARE_READ,
297 FILE_SYNCHRONOUS_IO_NONALERT);
298
299 if (!NT_SUCCESS(Status))
300 {
301 DPRINT("Could not font file: %wZ\n", FileName);
302 return 0;
303 }
304
305 Status = MmCreateSection((PVOID)&SectionObject, SECTION_ALL_ACCESS,
306 NULL, NULL, PAGE_READONLY,
307 0, FileHandle, NULL);
308 if (!NT_SUCCESS(Status))
309 {
310 DPRINT("Could not map file: %wZ\n", FileName);
311 ZwClose(FileHandle);
312 return 0;
313 }
314
315 ZwClose(FileHandle);
316
317 Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
318 if (!NT_SUCCESS(Status))
319 {
320 DPRINT("Could not map file: %wZ\n", FileName);
321 return Status;
322 }
323
324 IntLockFreeType;
325 Error = FT_New_Memory_Face(
326 library,
327 Buffer,
328 ViewSize,
329 0,
330 &Face);
331 IntUnLockFreeType;
332
333 if (Error)
334 {
335 if (Error == FT_Err_Unknown_File_Format)
336 DPRINT("Unknown font file format\n");
337 else
338 DPRINT("Error reading font file (error code: %u)\n", Error);
339 ObDereferenceObject(SectionObject);
340 return 0;
341 }
342
343 Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
344 if (!Entry)
345 {
346 FT_Done_Face(Face);
347 ObDereferenceObject(SectionObject);
348 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
349 return 0;
350 }
351
352 FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), TAG_FONTOBJ);
353 if(FontGDI == NULL)
354 {
355 FT_Done_Face(Face);
356 ObDereferenceObject(SectionObject);
357 ExFreePool(Entry);
358 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
359 return 0;
360 }
361
362 /* FontGDI->Filename = FileName; perform strcpy */
363 FontGDI->face = Face;
364
365 /* FIXME: Complete text metrics */
366 FontGDI->TextMetric.tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
367 FontGDI->TextMetric.tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
368 FontGDI->TextMetric.tmHeight = (Face->size->metrics.ascender -
369 Face->size->metrics.descender) >> 6;
370
371 DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
372 DPRINT("Num glyphs: %u\n", Face->num_glyphs);
373
374 /* Add this font resource to the font table */
375
376 Entry->Font = FontGDI;
377 Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
378 RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name);
379 RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
380
381 if (Characteristics & FR_PRIVATE)
382 {
383 PW32PROCESS Win32Process = PsGetCurrentProcessWin32Process();
384 IntLockProcessPrivateFonts(Win32Process);
385 InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
386 IntUnLockProcessPrivateFonts(Win32Process);
387 }
388 else
389 {
390 IntLockGlobalFonts;
391 InsertTailList(&FontListHead, &Entry->ListEntry);
392 IntUnLockGlobalFonts;
393 }
394
395 return 1;
396 }
397
398 BOOL FASTCALL
399 IntIsFontRenderingEnabled(VOID)
400 {
401 BOOL Ret = RenderingEnabled;
402 HDC hDC;
403
404 hDC = IntGetScreenDC();
405 if (hDC)
406 Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
407
408 return Ret;
409 }
410
411 VOID FASTCALL
412 IntEnableFontRendering(BOOL Enable)
413 {
414 RenderingEnabled = Enable;
415 }
416
417 FT_Render_Mode FASTCALL
418 IntGetFontRenderMode(LOGFONTW *logfont)
419 {
420 switch(logfont->lfQuality)
421 {
422 case NONANTIALIASED_QUALITY:
423 return FT_RENDER_MODE_MONO;
424 case DRAFT_QUALITY:
425 return FT_RENDER_MODE_LIGHT;
426 /* case CLEARTYPE_QUALITY:
427 return FT_RENDER_MODE_LCD; */
428 }
429 return FT_RENDER_MODE_NORMAL;
430 }
431
432 int
433 STDCALL
434 NtGdiAddFontResource(PUNICODE_STRING Filename, DWORD fl)
435 {
436 UNICODE_STRING SafeFileName;
437 PWSTR src;
438 NTSTATUS Status;
439 int Ret;
440
441 /* Copy the UNICODE_STRING structure */
442 Status = MmCopyFromCaller(&SafeFileName, Filename, sizeof(UNICODE_STRING));
443 if(!NT_SUCCESS(Status))
444 {
445 SetLastNtError(Status);
446 return 0;
447 }
448
449 /* Reserve for prepending '\??\' */
450 SafeFileName.Length += 4 * sizeof(WCHAR);
451 SafeFileName.MaximumLength += 4 * sizeof(WCHAR);
452
453 src = SafeFileName.Buffer;
454 SafeFileName.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, SafeFileName.MaximumLength, TAG_STRING);
455 if(!SafeFileName.Buffer)
456 {
457 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
458 return 0;
459 }
460
461 /* Prepend '\??\' */
462 RtlCopyMemory(SafeFileName.Buffer, L"\\??\\", 4 * sizeof(WCHAR));
463
464 Status = MmCopyFromCaller(SafeFileName.Buffer + 4, src, SafeFileName.MaximumLength - (4 * sizeof(WCHAR)));
465 if(!NT_SUCCESS(Status))
466 {
467 ExFreePool(SafeFileName.Buffer);
468 SetLastNtError(Status);
469 return 0;
470 }
471
472 Ret = IntGdiAddFontResource(&SafeFileName, fl);
473
474 ExFreePool(SafeFileName.Buffer);
475 return Ret;
476 }
477
478 NTSTATUS FASTCALL
479 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
480 {
481 PTEXTOBJ TextObj;
482 NTSTATUS Status = STATUS_SUCCESS;
483
484 *NewFont = TEXTOBJ_AllocText();
485 if (NULL != *NewFont)
486 {
487 TextObj = TEXTOBJ_LockText(*NewFont);
488 if (NULL != TextObj)
489 {
490 memcpy(&TextObj->logfont, lf, sizeof(LOGFONTW));
491 if (lf->lfEscapement != lf->lfOrientation)
492 {
493 /* this should really depend on whether GM_ADVANCED is set */
494 TextObj->logfont.lfOrientation = TextObj->logfont.lfEscapement;
495 }
496 TEXTOBJ_UnlockText(TextObj);
497 }
498 else
499 {
500 /* FIXME */
501 /* ASSERT(FALSE);*/
502 Status = STATUS_INVALID_HANDLE;
503 }
504 }
505 else
506 {
507 Status = STATUS_NO_MEMORY;
508 }
509
510 return Status;
511 }
512
513 HFONT
514 STDCALL
515 NtGdiCreateFont(int Height,
516 int Width,
517 int Escapement,
518 int Orientation,
519 int Weight,
520 DWORD Italic,
521 DWORD Underline,
522 DWORD StrikeOut,
523 DWORD CharSet,
524 DWORD OutputPrecision,
525 DWORD ClipPrecision,
526 DWORD Quality,
527 DWORD PitchAndFamily,
528 LPCWSTR Face)
529 {
530 LOGFONTW logfont;
531 HFONT NewFont;
532 NTSTATUS Status = STATUS_SUCCESS;
533
534 logfont.lfHeight = Height;
535 logfont.lfWidth = Width;
536 logfont.lfEscapement = Escapement;
537 logfont.lfOrientation = Orientation;
538 logfont.lfWeight = Weight;
539 logfont.lfItalic = Italic;
540 logfont.lfUnderline = Underline;
541 logfont.lfStrikeOut = StrikeOut;
542 logfont.lfCharSet = CharSet;
543 logfont.lfOutPrecision = OutputPrecision;
544 logfont.lfClipPrecision = ClipPrecision;
545 logfont.lfQuality = Quality;
546 logfont.lfPitchAndFamily = PitchAndFamily;
547
548 if (NULL != Face)
549 {
550 int Size = sizeof(logfont.lfFaceName) / sizeof(WCHAR);
551 wcsncpy((wchar_t *)logfont.lfFaceName, Face, Size - 1);
552 /* Be 101% sure to have '\0' at end of string */
553 logfont.lfFaceName[Size - 1] = '\0';
554 }
555 else
556 {
557 logfont.lfFaceName[0] = L'\0';
558 }
559
560 if (NT_SUCCESS(Status))
561 {
562 Status = TextIntCreateFontIndirect(&logfont, &NewFont);
563 }
564
565 return NT_SUCCESS(Status) ? NewFont : NULL;
566 }
567
568 HFONT
569 STDCALL
570 NtGdiCreateFontIndirect(CONST LPLOGFONTW lf)
571 {
572 LOGFONTW SafeLogfont;
573 HFONT NewFont;
574 NTSTATUS Status = STATUS_SUCCESS;
575
576 if (NULL != lf)
577 {
578 Status = MmCopyFromCaller(&SafeLogfont, lf, sizeof(LOGFONTW));
579 if (NT_SUCCESS(Status))
580 {
581 Status = TextIntCreateFontIndirect(&SafeLogfont, &NewFont);
582 }
583 }
584 else
585 {
586 Status = STATUS_INVALID_PARAMETER;
587 }
588
589 return NT_SUCCESS(Status) ? NewFont : NULL;
590 }
591
592 BOOL
593 STDCALL
594 NtGdiCreateScalableFontResource(DWORD Hidden,
595 LPCWSTR FontRes,
596 LPCWSTR FontFile,
597 LPCWSTR CurrentPath)
598 {
599 DPRINT1("NtGdiCreateScalableFontResource - is unimplemented, have a nice day and keep going");
600 return FALSE;
601 }
602
603 /*************************************************************************
604 * TranslateCharsetInfo
605 *
606 * Fills a CHARSETINFO structure for a character set, code page, or
607 * font. This allows making the correspondance between different labelings
608 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
609 * of the same encoding.
610 *
611 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
612 * only one codepage should be set in *Src.
613 *
614 * RETURNS
615 * TRUE on success, FALSE on failure.
616 *
617 */
618 static BOOLEAN STDCALL
619 IntTranslateCharsetInfo(PDWORD Src, /* [in]
620 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
621 if flags == TCI_SRCCHARSET: a character set value
622 if flags == TCI_SRCCODEPAGE: a code page value */
623 LPCHARSETINFO Cs, /* [out] structure to receive charset information */
624 DWORD Flags /* [in] determines interpretation of lpSrc */)
625 {
626 int Index = 0;
627
628 switch (Flags)
629 {
630 case TCI_SRCFONTSIG:
631 while (0 == (*Src >> Index & 0x0001) && Index < MAXTCIINDEX)
632 {
633 Index++;
634 }
635 break;
636 case TCI_SRCCODEPAGE:
637 while ((UINT) (Src) != FontTci[Index].ciACP && Index < MAXTCIINDEX)
638 {
639 Index++;
640 }
641 break;
642 case TCI_SRCCHARSET:
643 while ((UINT) (Src) != FontTci[Index].ciCharset && Index < MAXTCIINDEX)
644 {
645 Index++;
646 }
647 break;
648 default:
649 return FALSE;
650 }
651
652 if (MAXTCIINDEX <= Index || DEFAULT_CHARSET == FontTci[Index].ciCharset)
653 {
654 return FALSE;
655 }
656
657 memcpy(Cs, &FontTci[Index], sizeof(CHARSETINFO));
658
659 return TRUE;
660 }
661
662 BOOL STDCALL
663 NtGdiTranslateCharsetInfo(PDWORD Src,
664 LPCHARSETINFO UnsafeCs,
665 DWORD Flags)
666 {
667 CHARSETINFO Cs;
668 BOOLEAN Ret;
669 NTSTATUS Status;
670
671 Ret = IntTranslateCharsetInfo(Src, &Cs, Flags);
672 if (Ret)
673 {
674 Status = MmCopyToCaller(UnsafeCs, &Cs, sizeof(CHARSETINFO));
675 if (! NT_SUCCESS(Status))
676 {
677 SetLastWin32Error(ERROR_INVALID_PARAMETER);
678 return FALSE;
679 }
680 }
681
682 return (BOOL) Ret;
683 }
684
685 static void FASTCALL
686 FillTM(TEXTMETRICW *TM, FT_Face Face, TT_OS2 *pOS2, TT_HoriHeader *pHori)
687 {
688 FT_Fixed XScale, YScale;
689 int Ascent, Descent;
690
691 XScale = Face->size->metrics.x_scale;
692 YScale = Face->size->metrics.y_scale;
693
694 if (0 == pOS2->usWinAscent + pOS2->usWinDescent)
695 {
696 Ascent = pHori->Ascender;
697 Descent = -pHori->Descender;
698 }
699 else
700 {
701 Ascent = pOS2->usWinAscent;
702 Descent = pOS2->usWinDescent;
703 }
704
705 #if 0 /* This (Wine) code doesn't seem to work correctly for us */
706 TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
707 TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
708 #else
709 TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* units above baseline */
710 TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* units below baseline */
711 #endif
712 TM->tmInternalLeading = (FT_MulFix(Ascent + Descent
713 - Face->units_per_EM, YScale) + 32) >> 6;
714
715 TM->tmHeight = TM->tmAscent + TM->tmDescent;
716
717 /* MSDN says:
718 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
719 */
720 TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
721 - ((Ascent + Descent)
722 - (pHori->Ascender - pHori->Descender)),
723 YScale) + 32) >> 6);
724
725 TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
726 if (0 == TM->tmAveCharWidth)
727 {
728 TM->tmAveCharWidth = 1;
729 }
730 TM->tmMaxCharWidth = (FT_MulFix(Face->bbox.xMax - Face->bbox.xMin,
731 XScale) + 32) >> 6;
732 TM->tmWeight = pOS2->usWeightClass;
733 TM->tmOverhang = 0;
734 TM->tmDigitizedAspectX = 300;
735 TM->tmDigitizedAspectY = 300;
736 TM->tmFirstChar = pOS2->usFirstCharIndex;
737 TM->tmLastChar = pOS2->usLastCharIndex;
738 TM->tmDefaultChar = pOS2->usDefaultChar;
739 TM->tmBreakChar = L'\0' != pOS2->usBreakChar ? pOS2->usBreakChar : ' ';
740 TM->tmItalic = (Face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0;
741 TM->tmUnderlined = 0; /* entry in OS2 table */
742 TM->tmStruckOut = 0; /* entry in OS2 table */
743
744 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
745 if (! FT_IS_FIXED_WIDTH(Face))
746 {
747 TM->tmPitchAndFamily = TMPF_FIXED_PITCH;
748 }
749 else
750 {
751 TM->tmPitchAndFamily = 0;
752 }
753
754 switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
755 {
756 case PAN_FAMILY_SCRIPT:
757 TM->tmPitchAndFamily |= FF_SCRIPT;
758 break;
759 case PAN_FAMILY_DECORATIVE:
760 case PAN_FAMILY_PICTORIAL:
761 TM->tmPitchAndFamily |= FF_DECORATIVE;
762 break;
763 case PAN_FAMILY_TEXT_DISPLAY:
764 if (0 == TM->tmPitchAndFamily) /* fixed */
765 {
766 TM->tmPitchAndFamily = FF_MODERN;
767 }
768 else
769 {
770 switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
771 {
772 case PAN_SERIF_NORMAL_SANS:
773 case PAN_SERIF_OBTUSE_SANS:
774 case PAN_SERIF_PERP_SANS:
775 TM->tmPitchAndFamily |= FF_SWISS;
776 break;
777 default:
778 TM->tmPitchAndFamily |= FF_ROMAN;
779 break;
780 }
781 }
782 break;
783 default:
784 TM->tmPitchAndFamily |= FF_DONTCARE;
785 }
786
787 if (FT_IS_SCALABLE(Face))
788 {
789 TM->tmPitchAndFamily |= TMPF_VECTOR;
790 }
791 if (FT_IS_SFNT(Face))
792 {
793 TM->tmPitchAndFamily |= TMPF_TRUETYPE;
794 }
795
796 TM->tmCharSet = DEFAULT_CHARSET;
797 }
798
799 /*************************************************************
800 * IntGetOutlineTextMetrics
801 *
802 */
803 static unsigned FASTCALL
804 IntGetOutlineTextMetrics(PFONTGDI FontGDI, UINT Size,
805 OUTLINETEXTMETRICW *Otm)
806 {
807 unsigned Needed;
808 TT_OS2 *pOS2;
809 TT_HoriHeader *pHori;
810 TT_Postscript *pPost;
811 FT_Fixed XScale, YScale;
812 ANSI_STRING FamilyNameA, StyleNameA;
813 UNICODE_STRING FamilyNameW, StyleNameW, Regular;
814 char *Cp;
815
816 Needed = sizeof(OUTLINETEXTMETRICW);
817
818 RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name);
819 RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
820
821 RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name);
822 RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
823
824 /* These names should be read from the TT name table */
825
826 /* length of otmpFamilyName */
827 Needed += FamilyNameW.Length + sizeof(WCHAR);
828
829 RtlInitUnicodeString(&Regular, L"regular");
830 /* length of otmpFaceName */
831 if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
832 {
833 Needed += FamilyNameW.Length + sizeof(WCHAR); /* just the family name */
834 }
835 else
836 {
837 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
838 }
839
840 /* length of otmpStyleName */
841 Needed += StyleNameW.Length + sizeof(WCHAR);
842
843 /* length of otmpFullName */
844 Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
845
846 if (Size < Needed)
847 {
848 RtlFreeUnicodeString(&FamilyNameW);
849 RtlFreeUnicodeString(&StyleNameW);
850 return Needed;
851 }
852
853 XScale = FontGDI->face->size->metrics.x_scale;
854 YScale = FontGDI->face->size->metrics.y_scale;
855
856 IntLockFreeType;
857 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
858 if (NULL == pOS2)
859 {
860 IntUnLockFreeType;
861 DPRINT1("Can't find OS/2 table - not TT font?\n");
862 RtlFreeUnicodeString(&StyleNameW);
863 RtlFreeUnicodeString(&FamilyNameW);
864 return 0;
865 }
866
867 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
868 if (NULL == pHori)
869 {
870 IntUnLockFreeType;
871 DPRINT1("Can't find HHEA table - not TT font?\n");
872 RtlFreeUnicodeString(&StyleNameW);
873 RtlFreeUnicodeString(&FamilyNameW);
874 return 0;
875 }
876
877 pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* we can live with this failing */
878
879 Otm->otmSize = Needed;
880
881 FillTM(&Otm->otmTextMetrics, FontGDI->face, pOS2, pHori);
882
883 Otm->otmFiller = 0;
884 memcpy(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
885 Otm->otmfsSelection = pOS2->fsSelection;
886 Otm->otmfsType = pOS2->fsType;
887 Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
888 Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
889 Otm->otmItalicAngle = 0; /* POST table */
890 Otm->otmEMSquare = FontGDI->face->units_per_EM;
891 Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
892 Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
893 Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
894 Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
895 Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
896 Otm->otmrcFontBox.left = (FT_MulFix(FontGDI->face->bbox.xMin, XScale) + 32) >> 6;
897 Otm->otmrcFontBox.right = (FT_MulFix(FontGDI->face->bbox.xMax, XScale) + 32) >> 6;
898 Otm->otmrcFontBox.top = (FT_MulFix(FontGDI->face->bbox.yMax, YScale) + 32) >> 6;
899 Otm->otmrcFontBox.bottom = (FT_MulFix(FontGDI->face->bbox.yMin, YScale) + 32) >> 6;
900 Otm->otmMacAscent = 0; /* where do these come from ? */
901 Otm->otmMacDescent = 0;
902 Otm->otmMacLineGap = 0;
903 Otm->otmusMinimumPPEM = 0; /* TT Header */
904 Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6;
905 Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6;
906 Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6;
907 Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6;
908 Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6;
909 Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6;
910 Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6;
911 Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6;
912 Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6;
913 Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6;
914 if (NULL == pPost)
915 {
916 Otm->otmsUnderscoreSize = 0;
917 Otm->otmsUnderscorePosition = 0;
918 }
919 else
920 {
921 Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6;
922 Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
923 }
924
925 IntUnLockFreeType;
926
927 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
928 Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
929 Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
930 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
931 Cp += FamilyNameW.Length + sizeof(WCHAR);
932 Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
933 wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
934 Cp += StyleNameW.Length + sizeof(WCHAR);
935 Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
936 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
937 if (0 != RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
938 {
939 wcscat((WCHAR*) Cp, L" ");
940 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
941 Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
942 }
943 else
944 {
945 Cp += FamilyNameW.Length + sizeof(WCHAR);
946 }
947 Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
948 wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
949 wcscat((WCHAR*) Cp, L" ");
950 wcscat((WCHAR*) Cp, StyleNameW.Buffer);
951
952 RtlFreeUnicodeString(&StyleNameW);
953 RtlFreeUnicodeString(&FamilyNameW);
954
955 return Needed;
956 }
957
958 static PFONTGDI FASTCALL
959 FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
960 {
961 PLIST_ENTRY Entry;
962 PFONT_ENTRY CurrentEntry;
963 ANSI_STRING EntryFaceNameA;
964 UNICODE_STRING EntryFaceNameW;
965 FONTGDI *FontGDI;
966
967 Entry = Head->Flink;
968 while (Entry != Head)
969 {
970 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
971
972 FontGDI = CurrentEntry->Font;
973 ASSERT(FontGDI);
974
975 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
976 RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
977 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
978 {
979 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
980 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
981 }
982
983 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
984 {
985 RtlFreeUnicodeString(&EntryFaceNameW);
986 return FontGDI;
987 }
988
989 RtlFreeUnicodeString(&EntryFaceNameW);
990 Entry = Entry->Flink;
991 }
992
993 return NULL;
994 }
995
996 static PFONTGDI FASTCALL
997 FindFaceNameInLists(PUNICODE_STRING FaceName)
998 {
999 PW32PROCESS Win32Process;
1000 PFONTGDI Font;
1001
1002 /* Search the process local list */
1003 Win32Process = PsGetCurrentProcessWin32Process();
1004 IntLockProcessPrivateFonts(Win32Process);
1005 Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
1006 IntUnLockProcessPrivateFonts(Win32Process);
1007 if (NULL != Font)
1008 {
1009 return Font;
1010 }
1011
1012 /* Search the global list */
1013 IntLockGlobalFonts;
1014 Font = FindFaceNameInList(FaceName, &FontListHead);
1015 IntUnLockGlobalFonts;
1016
1017 return Font;
1018 }
1019
1020 static void FASTCALL
1021 FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
1022 {
1023 ANSI_STRING StyleA;
1024 UNICODE_STRING StyleW;
1025 TT_OS2 *pOS2;
1026 FONTSIGNATURE fs;
1027 DWORD fs_fsCsb0;
1028 CHARSETINFO CharSetInfo;
1029 unsigned i, Size;
1030 OUTLINETEXTMETRICW *Otm;
1031 LOGFONTW *Lf;
1032 TEXTMETRICW *TM;
1033 NEWTEXTMETRICW *Ntm;
1034
1035 RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
1036 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
1037 Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
1038 if (NULL == Otm)
1039 {
1040 return;
1041 }
1042 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
1043
1044 Lf = &Info->EnumLogFontEx.elfLogFont;
1045 TM = &Otm->otmTextMetrics;
1046
1047 Lf->lfHeight = TM->tmHeight;
1048 Lf->lfWidth = TM->tmAveCharWidth;
1049 Lf->lfWeight = TM->tmWeight;
1050 Lf->lfItalic = TM->tmItalic;
1051 Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
1052 Lf->lfCharSet = TM->tmCharSet;
1053 Lf->lfOutPrecision = OUT_STROKE_PRECIS;
1054 Lf->lfClipPrecision = CLIP_STROKE_PRECIS;
1055 Lf->lfQuality = DRAFT_QUALITY;
1056
1057 Ntm = &Info->NewTextMetricEx.ntmTm;
1058 Ntm->tmHeight = TM->tmHeight;
1059 Ntm->tmAscent = TM->tmAscent;
1060 Ntm->tmDescent = TM->tmDescent;
1061 Ntm->tmInternalLeading = TM->tmInternalLeading;
1062 Ntm->tmExternalLeading = TM->tmExternalLeading;
1063 Ntm->tmAveCharWidth = TM->tmAveCharWidth;
1064 Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
1065 Ntm->tmWeight = TM->tmWeight;
1066 Ntm->tmOverhang = TM->tmOverhang;
1067 Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
1068 Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
1069 Ntm->tmFirstChar = TM->tmFirstChar;
1070 Ntm->tmLastChar = TM->tmLastChar;
1071 Ntm->tmDefaultChar = TM->tmDefaultChar;
1072 Ntm->tmBreakChar = TM->tmBreakChar;
1073 Ntm->tmItalic = TM->tmItalic;
1074 Ntm->tmUnderlined = TM->tmUnderlined;
1075 Ntm->tmStruckOut = TM->tmStruckOut;
1076 Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
1077 Ntm->tmCharSet = TM->tmCharSet;
1078 Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
1079 if (550 < TM->tmWeight)
1080 {
1081 Ntm->ntmFlags |= NTM_BOLD;
1082 }
1083 if (0 == Ntm->ntmFlags)
1084 {
1085 Ntm->ntmFlags = NTM_REGULAR;
1086 }
1087
1088 Ntm->ntmSizeEM = Otm->otmEMSquare;
1089 Ntm->ntmCellHeight = 0;
1090 Ntm->ntmAvgWidth = 0;
1091
1092 Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
1093 ? TRUETYPE_FONTTYPE : 0);
1094 if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
1095 {
1096 Info->FontType |= RASTER_FONTTYPE;
1097 }
1098
1099 ExFreePool(Otm);
1100
1101 wcsncpy(Info->EnumLogFontEx.elfLogFont.lfFaceName, FaceName, LF_FACESIZE);
1102 wcsncpy(Info->EnumLogFontEx.elfFullName, FaceName, LF_FULLFACESIZE);
1103 RtlInitAnsiString(&StyleA, FontGDI->face->style_name);
1104 RtlAnsiStringToUnicodeString(&StyleW, &StyleA, TRUE);
1105 wcsncpy(Info->EnumLogFontEx.elfStyle, StyleW.Buffer, LF_FACESIZE);
1106 RtlFreeUnicodeString(&StyleW);
1107
1108 Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
1109 Info->EnumLogFontEx.elfScript[0] = L'\0';
1110 IntLockFreeType;
1111 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
1112 IntUnLockFreeType;
1113 if (NULL != pOS2)
1114 {
1115 Info->NewTextMetricEx.ntmFontSig.fsCsb[0] = pOS2->ulCodePageRange1;
1116 Info->NewTextMetricEx.ntmFontSig.fsCsb[1] = pOS2->ulCodePageRange2;
1117 Info->NewTextMetricEx.ntmFontSig.fsUsb[0] = pOS2->ulUnicodeRange1;
1118 Info->NewTextMetricEx.ntmFontSig.fsUsb[1] = pOS2->ulUnicodeRange2;
1119 Info->NewTextMetricEx.ntmFontSig.fsUsb[2] = pOS2->ulUnicodeRange3;
1120 Info->NewTextMetricEx.ntmFontSig.fsUsb[3] = pOS2->ulUnicodeRange4;
1121
1122 fs_fsCsb0 = pOS2->ulCodePageRange1;
1123 if (0 == pOS2->version)
1124 {
1125 FT_UInt Dummy;
1126
1127 if (FT_Get_First_Char(FontGDI->face, &Dummy) < 0x100)
1128 {
1129 fs_fsCsb0 |= 1;
1130 }
1131 else
1132 {
1133 fs_fsCsb0 |= 1L << 31;
1134 }
1135 }
1136 if (0 == fs_fsCsb0)
1137 { /* let's see if we can find any interesting cmaps */
1138 for (i = 0; i < FontGDI->face->num_charmaps; i++)
1139 {
1140 switch (FontGDI->face->charmaps[i]->encoding)
1141 {
1142 case ft_encoding_unicode:
1143 case ft_encoding_apple_roman:
1144 fs_fsCsb0 |= 1;
1145 break;
1146 case ft_encoding_symbol:
1147 fs_fsCsb0 |= 1L << 31;
1148 break;
1149 default:
1150 break;
1151 }
1152 }
1153 }
1154
1155 for(i = 0; i < 32; i++)
1156 {
1157 if (0 != (fs_fsCsb0 & (1L << i)))
1158 {
1159 fs.fsCsb[0] = 1L << i;
1160 fs.fsCsb[1] = 0;
1161 if (! IntTranslateCharsetInfo(fs.fsCsb, &CharSetInfo, TCI_SRCFONTSIG))
1162 {
1163 CharSetInfo.ciCharset = DEFAULT_CHARSET;
1164 }
1165 if (31 == i)
1166 {
1167 CharSetInfo.ciCharset = SYMBOL_CHARSET;
1168 }
1169 if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
1170 {
1171 Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
1172 if (NULL != ElfScripts[i])
1173 {
1174 wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
1175 }
1176 else
1177 {
1178 DPRINT1("Unknown elfscript for bit %d\n", i);
1179 }
1180 }
1181 }
1182 }
1183 }
1184 }
1185
1186 static int FASTCALL
1187 FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
1188 {
1189 DWORD i;
1190 UNICODE_STRING InfoFaceName;
1191
1192 for (i = 0; i < InfoEntries; i++)
1193 {
1194 RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
1195 if (0 == RtlCompareUnicodeString(&InfoFaceName, FaceName, TRUE))
1196 {
1197 return i;
1198 }
1199 }
1200
1201 return -1;
1202 }
1203
1204 static BOOLEAN FASTCALL
1205 FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
1206 PFONTFAMILYINFO Info, DWORD InfoEntries)
1207 {
1208 UNICODE_STRING LogFontFaceName;
1209
1210 RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
1211 if (0 != LogFontFaceName.Length
1212 && 0 != RtlCompareUnicodeString(&LogFontFaceName, FaceName, TRUE))
1213 {
1214 return FALSE;
1215 }
1216
1217 return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
1218 }
1219
1220 static BOOLEAN FASTCALL
1221 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
1222 PFONTFAMILYINFO Info,
1223 DWORD *Count,
1224 DWORD Size,
1225 PLIST_ENTRY Head)
1226 {
1227 PLIST_ENTRY Entry;
1228 PFONT_ENTRY CurrentEntry;
1229 ANSI_STRING EntryFaceNameA;
1230 UNICODE_STRING EntryFaceNameW;
1231 FONTGDI *FontGDI;
1232
1233 Entry = Head->Flink;
1234 while (Entry != Head)
1235 {
1236 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
1237
1238 FontGDI = CurrentEntry->Font;
1239 ASSERT(FontGDI);
1240
1241 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
1242 RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
1243 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
1244 {
1245 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
1246 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
1247 }
1248
1249 if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
1250 {
1251 if (*Count < Size)
1252 {
1253 FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
1254 }
1255 (*Count)++;
1256 }
1257 RtlFreeUnicodeString(&EntryFaceNameW);
1258 Entry = Entry->Flink;
1259 }
1260
1261 return TRUE;
1262 }
1263
1264 typedef struct FontFamilyInfoCallbackContext
1265 {
1266 LPLOGFONTW LogFont;
1267 PFONTFAMILYINFO Info;
1268 DWORD Count;
1269 DWORD Size;
1270 } FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
1271
1272 static NTSTATUS STDCALL
1273 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
1274 IN PVOID ValueData, IN ULONG ValueLength,
1275 IN PVOID Context, IN PVOID EntryContext)
1276 {
1277 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
1278 UNICODE_STRING RegistryName, RegistryValue;
1279 int Existing;
1280 PFONTGDI FontGDI;
1281
1282 if (REG_SZ != ValueType)
1283 {
1284 return STATUS_SUCCESS;
1285 }
1286 InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
1287 RtlInitUnicodeString(&RegistryName, ValueName);
1288
1289 /* Do we need to include this font family? */
1290 if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
1291 min(InfoContext->Count, InfoContext->Size)))
1292 {
1293 RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
1294 Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
1295 min(InfoContext->Count, InfoContext->Size));
1296 if (0 <= Existing)
1297 {
1298 /* We already have the information about the "real" font. Just copy it */
1299 if (InfoContext->Count < InfoContext->Size)
1300 {
1301 InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
1302 wcsncpy(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
1303 RegistryName.Buffer, LF_FACESIZE);
1304 }
1305 InfoContext->Count++;
1306 return STATUS_SUCCESS;
1307 }
1308
1309 /* Try to find information about the "real" font */
1310 FontGDI = FindFaceNameInLists(&RegistryValue);
1311 if (NULL == FontGDI)
1312 {
1313 /* "Real" font not found, discard this registry entry */
1314 return STATUS_SUCCESS;
1315 }
1316
1317 /* Return info about the "real" font but with the name of the alias */
1318 if (InfoContext->Count < InfoContext->Size)
1319 {
1320 FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
1321 RegistryName.Buffer, FontGDI);
1322 }
1323 InfoContext->Count++;
1324 return STATUS_SUCCESS;
1325 }
1326
1327 return STATUS_SUCCESS;
1328 }
1329
1330 static BOOLEAN FASTCALL
1331 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
1332 PFONTFAMILYINFO Info,
1333 DWORD *Count,
1334 DWORD Size)
1335 {
1336 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1337 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
1338 NTSTATUS Status;
1339
1340 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\SysFontSubstitutes
1341 The real work is done in the registry callback function */
1342 Context.LogFont = LogFont;
1343 Context.Info = Info;
1344 Context.Count = *Count;
1345 Context.Size = Size;
1346
1347 QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
1348 QueryTable[0].Flags = 0;
1349 QueryTable[0].Name = NULL;
1350 QueryTable[0].EntryContext = NULL;
1351 QueryTable[0].DefaultType = REG_NONE;
1352 QueryTable[0].DefaultData = NULL;
1353 QueryTable[0].DefaultLength = 0;
1354
1355 QueryTable[1].QueryRoutine = NULL;
1356 QueryTable[1].Name = NULL;
1357
1358 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
1359 L"SysFontSubstitutes",
1360 QueryTable,
1361 &Context,
1362 NULL);
1363 if (NT_SUCCESS(Status))
1364 {
1365 *Count = Context.Count;
1366 }
1367
1368 return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
1369 }
1370
1371 int STDCALL
1372 NtGdiGetFontFamilyInfo(HDC Dc,
1373 LPLOGFONTW UnsafeLogFont,
1374 PFONTFAMILYINFO UnsafeInfo,
1375 DWORD Size)
1376 {
1377 NTSTATUS Status;
1378 LOGFONTW LogFont;
1379 PFONTFAMILYINFO Info;
1380 DWORD Count;
1381 PW32PROCESS Win32Process;
1382
1383 /* Make a safe copy */
1384 Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
1385 if (! NT_SUCCESS(Status))
1386 {
1387 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1388 return -1;
1389 }
1390
1391 /* Allocate space for a safe copy */
1392 Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), TAG_GDITEXT);
1393 if (NULL == Info)
1394 {
1395 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1396 return -1;
1397 }
1398
1399 /* Enumerate font families in the global list */
1400 IntLockGlobalFonts;
1401 Count = 0;
1402 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
1403 {
1404 IntUnLockGlobalFonts;
1405 ExFreePool(Info);
1406 return -1;
1407 }
1408 IntUnLockGlobalFonts;
1409
1410 /* Enumerate font families in the process local list */
1411 Win32Process = PsGetCurrentProcessWin32Process();
1412 IntLockProcessPrivateFonts(Win32Process);
1413 if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
1414 &Win32Process->PrivateFontListHead))
1415 {
1416 IntUnLockProcessPrivateFonts(Win32Process);
1417 ExFreePool(Info);
1418 return -1;
1419 }
1420 IntUnLockProcessPrivateFonts(Win32Process);
1421
1422 /* Enumerate font families in the registry */
1423 if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
1424 {
1425 ExFreePool(Info);
1426 return -1;
1427 }
1428
1429 /* Return data to caller */
1430 if (0 != Count)
1431 {
1432 Status = MmCopyToCaller(UnsafeInfo, Info,
1433 (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
1434 if (! NT_SUCCESS(Status))
1435 {
1436 ExFreePool(Info);
1437 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1438 return -1;
1439 }
1440 }
1441
1442 ExFreePool(Info);
1443
1444 return Count;
1445 }
1446
1447 int
1448 STDCALL
1449 NtGdiEnumFonts(HDC hDC,
1450 LPCWSTR FaceName,
1451 FONTENUMPROCW FontFunc,
1452 LPARAM lParam)
1453 {
1454 UNIMPLEMENTED;
1455 return 0;
1456 }
1457 FT_Glyph STDCALL
1458 NtGdiGlyphCacheGet(
1459 FT_Face Face,
1460 INT GlyphIndex,
1461 INT Height)
1462 {
1463 PLIST_ENTRY CurrentEntry;
1464 PFONT_CACHE_ENTRY FontEntry;
1465
1466 // DbgPrint("CacheGet\n");
1467
1468 CurrentEntry = FontCacheListHead.Flink;
1469 while (CurrentEntry != &FontCacheListHead)
1470 {
1471 FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
1472 if (FontEntry->Face == Face &&
1473 FontEntry->GlyphIndex == GlyphIndex &&
1474 FontEntry->Height == Height)
1475 break;
1476 CurrentEntry = CurrentEntry->Flink;
1477 }
1478
1479 if (CurrentEntry == &FontCacheListHead) {
1480 // DbgPrint("Miss! %x\n", FontEntry->Glyph);
1481 Misses++;
1482 if (Misses>100) {
1483 DbgPrint ("Hits: %d Misses: %d\n", Hits, Misses);
1484 Hits = Misses = 0;
1485 }
1486 return NULL;
1487 }
1488
1489 RemoveEntryList(CurrentEntry);
1490 InsertHeadList(&FontCacheListHead, CurrentEntry);
1491
1492 // DbgPrint("Hit! %x\n", FontEntry->Glyph);
1493 Hits++;
1494 if (Hits>100) {
1495 DbgPrint ("Hits: %d Misses: %d\n", Hits, Misses);
1496 Hits = Misses = 0;
1497 }
1498 return FontEntry->Glyph;
1499 }
1500
1501 FT_Glyph STDCALL
1502 NtGdiGlyphCacheSet(
1503 FT_Face Face,
1504 INT GlyphIndex,
1505 INT Height,
1506 FT_GlyphSlot GlyphSlot,
1507 FT_Render_Mode RenderMode)
1508 {
1509 FT_Glyph GlyphCopy;
1510 INT error;
1511 PFONT_CACHE_ENTRY NewEntry;
1512
1513 // DbgPrint("CacheSet.\n");
1514
1515 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
1516 if (error)
1517 {
1518 DbgPrint("Failure caching glyph.\n");
1519 return NULL;
1520 };
1521 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
1522 if (error)
1523 {
1524 DbgPrint("Failure rendering glyph.\n");
1525 return NULL;
1526 };
1527
1528 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
1529 if (!NewEntry)
1530 {
1531 DbgPrint("Alloc failure caching glyph.\n");
1532 FT_Done_Glyph(GlyphCopy);
1533 return NULL;
1534 }
1535
1536 NewEntry->GlyphIndex = GlyphIndex;
1537 NewEntry->Face = Face;
1538 NewEntry->Glyph = GlyphCopy;
1539 NewEntry->Height = Height;
1540
1541 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
1542 if (FontCacheNumEntries++ > MAX_FONT_CACHE) {
1543 NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
1544 FT_Done_Glyph(NewEntry->Glyph);
1545 RemoveTailList(&FontCacheListHead);
1546 ExFreePool(NewEntry);
1547 FontCacheNumEntries--;
1548 }
1549
1550 // DbgPrint("Returning the glyphcopy: %x\n", GlyphCopy);
1551
1552 return GlyphCopy;
1553 }
1554
1555 BOOL STDCALL
1556 NtGdiExtTextOut(
1557 HDC hDC,
1558 INT XStart,
1559 INT YStart,
1560 UINT fuOptions,
1561 CONST RECT *lprc,
1562 LPCWSTR String,
1563 UINT Count,
1564 CONST INT *UnsafeDx)
1565 {
1566 /*
1567 * FIXME:
1568 * Call EngTextOut, which does the real work (calling DrvTextOut where
1569 * appropriate)
1570 */
1571
1572 DC *dc;
1573 SURFOBJ *SurfObj;
1574 BITMAPOBJ *BitmapObj = NULL;
1575 int error, glyph_index, n, i;
1576 FT_Face face;
1577 FT_GlyphSlot glyph;
1578 FT_Glyph realglyph;
1579 FT_BitmapGlyph realglyph2;
1580 LONGLONG TextLeft, RealXStart;
1581 ULONG TextTop, previous, BackgroundLeft;
1582 FT_Bool use_kerning;
1583 RECTL DestRect, MaskRect, SpecifiedDestRect;
1584 POINTL SourcePoint, BrushOrigin;
1585 HBRUSH hBrushFg = NULL;
1586 PGDIBRUSHOBJ BrushFg = NULL;
1587 GDIBRUSHINST BrushFgInst;
1588 HBRUSH hBrushBg = NULL;
1589 PGDIBRUSHOBJ BrushBg = NULL;
1590 GDIBRUSHINST BrushBgInst;
1591 HBITMAP HSourceGlyph;
1592 SURFOBJ *SourceGlyphSurf;
1593 SIZEL bitSize;
1594 FT_CharMap found = 0, charmap;
1595 INT yoff;
1596 FONTOBJ *FontObj;
1597 PFONTGDI FontGDI;
1598 PTEXTOBJ TextObj = NULL;
1599 PPALGDI PalDestGDI;
1600 XLATEOBJ *XlateObj=NULL, *XlateObj2=NULL;
1601 ULONG Mode;
1602 FT_Render_Mode RenderMode;
1603 BOOLEAN Render;
1604 NTSTATUS Status;
1605 INT *Dx = NULL;
1606 POINT Start;
1607 BOOL DoBreak = FALSE;
1608
1609 // TODO: Write test-cases to exactly match real Windows in different
1610 // bad parameters (e.g. does Windows check the DC or the RECT first?).
1611 dc = DC_LockDc(hDC);
1612 if (!dc)
1613 {
1614 SetLastWin32Error(ERROR_INVALID_HANDLE);
1615 return FALSE;
1616 }
1617 if (dc->IsIC)
1618 {
1619 DC_UnlockDc(dc);
1620 /* Yes, Windows really returns TRUE in this case */
1621 return TRUE;
1622 }
1623
1624 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
1625 {
1626 // At least one of the two flags were specified. Copy lprc. Once.
1627 Status = MmCopyFromCaller(&SpecifiedDestRect, lprc, sizeof(RECT));
1628 if (!NT_SUCCESS(Status))
1629 {
1630 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1631 return FALSE;
1632 }
1633 IntLPtoDP(dc, (POINT *) &SpecifiedDestRect, 2);
1634 }
1635
1636 if (NULL != UnsafeDx && Count > 0)
1637 {
1638 Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
1639 if (NULL == Dx)
1640 {
1641 goto fail;
1642 }
1643 Status = MmCopyFromCaller(Dx, UnsafeDx, Count * sizeof(INT));
1644 if (! NT_SUCCESS(Status))
1645 {
1646 goto fail;
1647 }
1648 }
1649
1650 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
1651 if ( !BitmapObj )
1652 {
1653 goto fail;
1654 }
1655 SurfObj = &BitmapObj->SurfObj;
1656 ASSERT(SurfObj);
1657
1658 Start.x = XStart; Start.y = YStart;
1659 IntLPtoDP(dc, &Start, 1);
1660
1661 RealXStart = (Start.x + dc->w.DCOrgX) << 6;
1662 YStart = Start.y + dc->w.DCOrgY;
1663
1664 /* Create the brushes */
1665 PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
1666 if ( !PalDestGDI )
1667 Mode = PAL_RGB;
1668 else
1669 {
1670 Mode = PalDestGDI->Mode;
1671 PALETTE_UnlockPalette(PalDestGDI);
1672 }
1673 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
1674 if ( !XlateObj )
1675 {
1676 goto fail;
1677 }
1678 hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor), 0);
1679 if ( !hBrushFg )
1680 {
1681 goto fail;
1682 }
1683 BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
1684 if ( !BrushFg )
1685 {
1686 goto fail;
1687 }
1688 IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);
1689 if ((fuOptions & ETO_OPAQUE) || dc->w.backgroundMode == OPAQUE)
1690 {
1691 hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor), 0);
1692 if ( !hBrushBg )
1693 {
1694 goto fail;
1695 }
1696 BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
1697 if ( !BrushBg )
1698 {
1699 goto fail;
1700 }
1701 IntGdiInitBrushInstance(&BrushBgInst, BrushBg, NULL);
1702 }
1703 XlateObj2 = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, Mode, NULL, dc->w.hPalette);
1704 if ( !XlateObj2 )
1705 {
1706 goto fail;
1707 }
1708
1709 SourcePoint.x = 0;
1710 SourcePoint.y = 0;
1711 MaskRect.left = 0;
1712 MaskRect.top = 0;
1713 BrushOrigin.x = 0;
1714 BrushOrigin.y = 0;
1715
1716 if ((fuOptions & ETO_OPAQUE) && lprc)
1717 {
1718 DestRect.left = SpecifiedDestRect.left + dc->w.DCOrgX;
1719 DestRect.top = SpecifiedDestRect.top + dc->w.DCOrgY;
1720 DestRect.right = SpecifiedDestRect.right + dc->w.DCOrgX;
1721 DestRect.bottom = SpecifiedDestRect.bottom + dc->w.DCOrgY;
1722 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
1723 IntEngBitBlt(
1724 &BitmapObj->SurfObj,
1725 NULL,
1726 NULL,
1727 dc->CombinedClip,
1728 NULL,
1729 &DestRect,
1730 &SourcePoint,
1731 &SourcePoint,
1732 &BrushBgInst.BrushObject,
1733 &BrushOrigin,
1734 ROP3_TO_ROP4(PATCOPY));
1735 fuOptions &= ~ETO_OPAQUE;
1736 }
1737 else
1738 {
1739 if (dc->w.backgroundMode == OPAQUE)
1740 {
1741 fuOptions |= ETO_OPAQUE;
1742 }
1743 }
1744
1745 TextObj = TEXTOBJ_LockText(dc->w.hFont);
1746 if(TextObj == NULL)
1747 {
1748 goto fail;
1749 }
1750
1751 FontObj = TextObj->Font;
1752 ASSERT(FontObj);
1753 FontGDI = ObjToGDI(FontObj, FONT);
1754 ASSERT(FontGDI);
1755
1756 IntLockFreeType;
1757 face = FontGDI->face;
1758 if (face->charmap == NULL)
1759 {
1760 DPRINT("WARNING: No charmap selected!\n");
1761 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
1762
1763 for (n = 0; n < face->num_charmaps; n++)
1764 {
1765 charmap = face->charmaps[n];
1766 DPRINT("found charmap encoding: %u\n", charmap->encoding);
1767 if (charmap->encoding != 0)
1768 {
1769 found = charmap;
1770 break;
1771 }
1772 }
1773 if (!found)
1774 {
1775 DPRINT1("WARNING: Could not find desired charmap!\n");
1776 }
1777 error = FT_Set_Charmap(face, found);
1778 if (error)
1779 {
1780 DPRINT1("WARNING: Could not set the charmap!\n");
1781 }
1782 }
1783
1784 Render = IntIsFontRenderingEnabled();
1785 if (Render)
1786 RenderMode = IntGetFontRenderMode(&TextObj->logfont);
1787 else
1788 RenderMode = FT_RENDER_MODE_MONO;
1789
1790 error = FT_Set_Pixel_Sizes(
1791 face,
1792 TextObj->logfont.lfWidth,
1793 /* FIXME should set character height if neg */
1794 (TextObj->logfont.lfHeight < 0 ?
1795 - TextObj->logfont.lfHeight :
1796 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
1797 if (error)
1798 {
1799 DPRINT1("Error in setting pixel sizes: %u\n", error);
1800 IntUnLockFreeType;
1801 goto fail;
1802 }
1803
1804 /*
1805 * Process the vertical alignment and determine the yoff.
1806 */
1807
1808 if (dc->w.textAlign & TA_BASELINE)
1809 yoff = 0;
1810 else if (dc->w.textAlign & TA_BOTTOM)
1811 yoff = -face->size->metrics.descender >> 6;
1812 else /* TA_TOP */
1813 yoff = face->size->metrics.ascender >> 6;
1814
1815 use_kerning = FT_HAS_KERNING(face);
1816 previous = 0;
1817
1818 /*
1819 * Process the horizontal alignment and modify XStart accordingly.
1820 */
1821
1822 if (dc->w.textAlign & (TA_RIGHT | TA_CENTER))
1823 {
1824 ULONGLONG TextWidth = 0;
1825 LPCWSTR TempText = String;
1826 int Start;
1827
1828 /*
1829 * Calculate width of the text.
1830 */
1831
1832 if (NULL != Dx)
1833 {
1834 Start = Count < 2 ? 0 : Count - 2;
1835 TextWidth = Count < 2 ? 0 : (Dx[Count - 2] << 6);
1836 }
1837 else
1838 {
1839 Start = 0;
1840 }
1841 TempText = String + Start;
1842
1843 for (i = Start; i < Count; i++)
1844 {
1845 glyph_index = FT_Get_Char_Index(face, *TempText);
1846 if (!(realglyph = NtGdiGlyphCacheGet(face, glyph_index, TextObj->logfont.lfHeight)))
1847 {
1848 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1849 if (error)
1850 {
1851 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1852 }
1853
1854 glyph = face->glyph;
1855 realglyph = NtGdiGlyphCacheSet(face, glyph_index, TextObj->logfont.lfHeight, glyph, RenderMode);
1856 }
1857 /* retrieve kerning distance */
1858 if (use_kerning && previous && glyph_index)
1859 {
1860 FT_Vector delta;
1861 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1862 TextWidth += delta.x;
1863 }
1864
1865 TextWidth += realglyph->advance.x >> 10;
1866
1867 previous = glyph_index;
1868 TempText++;
1869 }
1870
1871 previous = 0;
1872
1873 if (dc->w.textAlign & TA_RIGHT)
1874 {
1875 RealXStart -= TextWidth;
1876 }
1877 else
1878 {
1879 RealXStart -= TextWidth / 2;
1880 }
1881 }
1882
1883 TextLeft = RealXStart;
1884 TextTop = YStart;
1885 BackgroundLeft = (RealXStart + 32) >> 6;
1886
1887 /*
1888 * The main rendering loop.
1889 */
1890
1891 for (i = 0; i < Count; i++)
1892 {
1893 glyph_index = FT_Get_Char_Index(face, *String);
1894 if (!(realglyph = NtGdiGlyphCacheGet(face, glyph_index, TextObj->logfont.lfHeight)))
1895 {
1896 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1897
1898 if (error)
1899 {
1900 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1901 IntUnLockFreeType;
1902 goto fail;
1903 }
1904 glyph = face->glyph;
1905 realglyph = NtGdiGlyphCacheSet(face, glyph_index, TextObj->logfont.lfHeight, glyph, RenderMode);
1906 }
1907 // DbgPrint("realglyph: %x\n", realglyph);
1908 // DbgPrint("TextLeft: %d\n", TextLeft);
1909
1910 /* retrieve kerning distance and move pen position */
1911 if (use_kerning && previous && glyph_index && NULL == Dx)
1912 {
1913 FT_Vector delta;
1914 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1915 TextLeft += delta.x;
1916 }
1917 // DPRINT1("TextLeft: %d\n", TextLeft);
1918 // DPRINT1("TextTop: %d\n", TextTop);
1919
1920 if (realglyph->format == ft_glyph_format_outline)
1921 {
1922 DbgPrint("Should already be done\n");
1923 // error = FT_Render_Glyph(glyph, RenderMode);
1924 error = FT_Glyph_To_Bitmap(&realglyph, RenderMode, 0, 0);
1925 if (error)
1926 {
1927 DPRINT1("WARNING: Failed to render glyph!\n");
1928 goto fail;
1929 }
1930 }
1931 realglyph2 = (FT_BitmapGlyph)realglyph;
1932
1933 // DPRINT1("Pitch: %d\n", pitch);
1934 // DPRINT1("Advance: %d\n", realglyph->advance.x);
1935
1936 if (fuOptions & ETO_OPAQUE)
1937 {
1938 DestRect.left = BackgroundLeft;
1939 DestRect.right = (TextLeft + (realglyph->advance.x >> 10) + 32) >> 6;
1940 DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6);
1941 DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6);
1942 IntEngBitBlt(
1943 &BitmapObj->SurfObj,
1944 NULL,
1945 NULL,
1946 dc->CombinedClip,
1947 NULL,
1948 &DestRect,
1949 &SourcePoint,
1950 &SourcePoint,
1951 &BrushBgInst.BrushObject,
1952 &BrushOrigin,
1953 ROP3_TO_ROP4(PATCOPY));
1954 BackgroundLeft = DestRect.right;
1955 }
1956
1957 DestRect.left = ((TextLeft + 32) >> 6) + realglyph2->left;
1958 DestRect.right = DestRect.left + realglyph2->bitmap.width;
1959 DestRect.top = TextTop + yoff - realglyph2->top;
1960 DestRect.bottom = DestRect.top + realglyph2->bitmap.rows;
1961
1962 // DbgPrint("lrtb %d %d %d %d\n", DestRect.left, DestRect.right,
1963 // DestRect.top, DestRect.bottom);
1964 // DbgPrint("specified lrtb %d %d %d %d\n", SpecifiedDestRect.left, SpecifiedDestRect.right,
1965 // SpecifiedDestRect.top, SpecifiedDestRect.bottom);
1966 // DbgPrint ("dc->w.DCOrgX: %d\n", dc->w.DCOrgX);
1967
1968 bitSize.cx = realglyph2->bitmap.width;
1969 bitSize.cy = realglyph2->bitmap.rows;
1970 MaskRect.right = realglyph2->bitmap.width;
1971 MaskRect.bottom = realglyph2->bitmap.rows;
1972
1973 /*
1974 * We should create the bitmap out of the loop at the biggest possible
1975 * glyph size. Then use memset with 0 to clear it and sourcerect to
1976 * limit the work of the transbitblt.
1977 *
1978 * FIXME: DIB bitmaps should have an lDelta which is a multiple of 4.
1979 * Here we pass in the pitch from the FreeType bitmap, which is not
1980 * guaranteed to be a multiple of 4. If it's not, we should expand
1981 * the FreeType bitmap to a temporary bitmap.
1982 */
1983
1984 HSourceGlyph = EngCreateBitmap(bitSize, realglyph2->bitmap.pitch,
1985 (realglyph2->bitmap.pixel_mode == ft_pixel_mode_grays) ?
1986 BMF_8BPP : BMF_1BPP, BMF_TOPDOWN,
1987 realglyph2->bitmap.buffer);
1988 if ( !HSourceGlyph )
1989 {
1990 DPRINT1("WARNING: EngLockSurface() failed!\n");
1991 FT_Done_Glyph(realglyph);
1992 IntUnLockFreeType;
1993 goto fail;
1994 }
1995 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
1996 if ( !SourceGlyphSurf )
1997 {
1998 EngDeleteSurface((HSURF)HSourceGlyph);
1999 DPRINT1("WARNING: EngLockSurface() failed!\n");
2000 IntUnLockFreeType;
2001 goto fail;
2002 }
2003
2004 /*
2005 * Use the font data as a mask to paint onto the DCs surface using a
2006 * brush.
2007 */
2008
2009 if (lprc &&
2010 (fuOptions & ETO_CLIPPED) &&
2011 DestRect.right >= SpecifiedDestRect.right + dc->w.DCOrgX)
2012 {
2013 // We do the check '>=' instead of '>' to possibly save an iteration
2014 // through this loop, since it's breaking after the drawing is done,
2015 // and x is always incremented.
2016 DestRect.right = SpecifiedDestRect.right + dc->w.DCOrgX;
2017 DoBreak = TRUE;
2018 }
2019
2020 IntEngMaskBlt(
2021 SurfObj,
2022 SourceGlyphSurf,
2023 dc->CombinedClip,
2024 XlateObj,
2025 XlateObj2,
2026 &DestRect,
2027 &SourcePoint,
2028 (PPOINTL)&MaskRect,
2029 &BrushFgInst.BrushObject,
2030 &BrushOrigin);
2031
2032 EngUnlockSurface(SourceGlyphSurf);
2033 EngDeleteSurface((HSURF)HSourceGlyph);
2034
2035 if (DoBreak)
2036 {
2037 break;
2038 }
2039
2040 if (NULL == Dx)
2041 {
2042 TextLeft += realglyph->advance.x >> 10;
2043 // DbgPrint("new TextLeft: %d\n", TextLeft);
2044 }
2045 else
2046 {
2047 TextLeft += Dx[i] << 6;
2048 // DbgPrint("new TextLeft2: %d\n", TextLeft);
2049 }
2050 previous = glyph_index;
2051
2052 String++;
2053 }
2054
2055 IntUnLockFreeType;
2056
2057 EngDeleteXlate(XlateObj);
2058 EngDeleteXlate(XlateObj2);
2059 BITMAPOBJ_UnlockBitmap(BitmapObj);
2060 if(TextObj != NULL)
2061 TEXTOBJ_UnlockText(TextObj);
2062 if (hBrushBg != NULL)
2063 {
2064 BRUSHOBJ_UnlockBrush(BrushBg);
2065 NtGdiDeleteObject(hBrushBg);
2066 }
2067 BRUSHOBJ_UnlockBrush(BrushFg);
2068 NtGdiDeleteObject(hBrushFg);
2069 if (NULL != Dx)
2070 {
2071 ExFreePool(Dx);
2072 }
2073 DC_UnlockDc( dc );
2074
2075 return TRUE;
2076
2077 fail:
2078 if ( XlateObj2 != NULL )
2079 EngDeleteXlate(XlateObj2);
2080 if ( XlateObj != NULL )
2081 EngDeleteXlate(XlateObj);
2082 if(TextObj != NULL)
2083 TEXTOBJ_UnlockText(TextObj);
2084 BITMAPOBJ_UnlockBitmap(BitmapObj);
2085 if (hBrushBg != NULL)
2086 {
2087 BRUSHOBJ_UnlockBrush(BrushBg);
2088 NtGdiDeleteObject(hBrushBg);
2089 }
2090 if (hBrushFg != NULL)
2091 {
2092 BRUSHOBJ_UnlockBrush(BrushFg);
2093 NtGdiDeleteObject(hBrushFg);
2094 }
2095 if (NULL != Dx)
2096 {
2097 ExFreePool(Dx);
2098 }
2099 DC_UnlockDc(dc);
2100
2101 return FALSE;
2102 }
2103
2104 BOOL
2105 STDCALL
2106 NtGdiGetAspectRatioFilterEx(HDC hDC,
2107 LPSIZE AspectRatio)
2108 {
2109 UNIMPLEMENTED;
2110 return FALSE;
2111 }
2112
2113 BOOL
2114 STDCALL
2115 NtGdiGetCharABCWidths(HDC hDC,
2116 UINT FirstChar,
2117 UINT LastChar,
2118 LPABC abc)
2119 {
2120 LPABC SafeBuffer;
2121 PDC dc;
2122 PTEXTOBJ TextObj;
2123 PFONTGDI FontGDI;
2124 FT_Face face;
2125 FT_CharMap charmap, found = NULL;
2126 UINT i, glyph_index, BufferSize;
2127 HFONT hFont = 0;
2128 NTSTATUS Status;
2129
2130 if (LastChar < FirstChar)
2131 {
2132 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2133 return FALSE;
2134 }
2135
2136 BufferSize = (LastChar - FirstChar + 1) * sizeof(ABC);
2137 SafeBuffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
2138 if (SafeBuffer == NULL)
2139 {
2140 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2141 return FALSE;
2142 }
2143
2144 dc = DC_LockDc(hDC);
2145 if (dc == NULL)
2146 {
2147 ExFreePool(SafeBuffer);
2148 SetLastWin32Error(ERROR_INVALID_HANDLE);
2149 return FALSE;
2150 }
2151 hFont = dc->w.hFont;
2152 TextObj = TEXTOBJ_LockText(hFont);
2153 DC_UnlockDc(dc);
2154
2155 if (TextObj == NULL)
2156 {
2157 ExFreePool(SafeBuffer);
2158 SetLastWin32Error(ERROR_INVALID_HANDLE);
2159 return FALSE;
2160 }
2161
2162 FontGDI = ObjToGDI(TextObj->Font, FONT);
2163
2164 face = FontGDI->face;
2165 if (face->charmap == NULL)
2166 {
2167 for (i = 0; i < face->num_charmaps; i++)
2168 {
2169 charmap = face->charmaps[i];
2170 if (charmap->encoding != 0)
2171 {
2172 found = charmap;
2173 break;
2174 }
2175 }
2176
2177 if (!found)
2178 {
2179 DPRINT1("WARNING: Could not find desired charmap!\n");
2180 ExFreePool(SafeBuffer);
2181 SetLastWin32Error(ERROR_INVALID_HANDLE);
2182 return FALSE;
2183 }
2184
2185 IntLockFreeType;
2186 FT_Set_Charmap(face, found);
2187 IntUnLockFreeType;
2188 }
2189
2190 IntLockFreeType;
2191 FT_Set_Pixel_Sizes(face,
2192 TextObj->logfont.lfWidth,
2193 /* FIXME should set character height if neg */
2194 (TextObj->logfont.lfHeight < 0 ? - TextObj->logfont.lfHeight :
2195 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
2196
2197 for (i = FirstChar; i <= LastChar; i++)
2198 {
2199 int adv, lsb, bbx, left, right;
2200
2201 glyph_index = FT_Get_Char_Index(face, i);
2202 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2203
2204 left = (INT)face->glyph->metrics.horiBearingX & -64;
2205 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
2206 adv = (face->glyph->advance.x + 32) >> 6;
2207
2208 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
2209 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same!*/
2210
2211 lsb = left >> 6;
2212 bbx = (right - left) >> 6;
2213 /*
2214 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
2215 */
2216 SafeBuffer[i - FirstChar].abcA = lsb;
2217 SafeBuffer[i - FirstChar].abcB = bbx;
2218 SafeBuffer[i - FirstChar].abcC = adv - lsb - bbx;
2219 }
2220 IntUnLockFreeType;
2221 TEXTOBJ_UnlockText(TextObj);
2222 Status = MmCopyToCaller(abc, SafeBuffer, BufferSize);
2223 if (! NT_SUCCESS(Status))
2224 {
2225 SetLastNtError(Status);
2226 ExFreePool(SafeBuffer);
2227 return FALSE;
2228 }
2229 ExFreePool(SafeBuffer);
2230 DPRINT("NtGdiGetCharABCWidths Worked!\n");
2231 return TRUE;
2232 }
2233
2234 BOOL
2235 STDCALL
2236 NtGdiGetCharABCWidthsFloat(HDC hDC,
2237 UINT FirstChar,
2238 UINT LastChar,
2239 LPABCFLOAT abcF)
2240 {
2241 UNIMPLEMENTED;
2242 return FALSE;
2243 }
2244
2245 DWORD
2246 STDCALL
2247 NtGdiGetCharacterPlacement(HDC hDC,
2248 LPCWSTR String,
2249 int Count,
2250 int MaxExtent,
2251 LPGCP_RESULTSW Results,
2252 DWORD Flags)
2253 {
2254 UNIMPLEMENTED;
2255 return 0;
2256 }
2257
2258 BOOL
2259 STDCALL
2260 NtGdiGetCharWidth32(HDC hDC,
2261 UINT FirstChar,
2262 UINT LastChar,
2263 LPINT Buffer)
2264 {
2265 LPINT SafeBuffer;
2266 PDC dc;
2267 PTEXTOBJ TextObj;
2268 PFONTGDI FontGDI;
2269 FT_Face face;
2270 FT_CharMap charmap, found = NULL;
2271 UINT i, glyph_index, BufferSize;
2272 HFONT hFont = 0;
2273
2274 if (LastChar < FirstChar)
2275 {
2276 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2277 return FALSE;
2278 }
2279
2280 BufferSize = (LastChar - FirstChar + 1) * sizeof(INT);
2281 SafeBuffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
2282 if (SafeBuffer == NULL)
2283 {
2284 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2285 return FALSE;
2286 }
2287
2288 dc = DC_LockDc(hDC);
2289 if (dc == NULL)
2290 {
2291 ExFreePool(SafeBuffer);
2292 SetLastWin32Error(ERROR_INVALID_HANDLE);
2293 return FALSE;
2294 }
2295 hFont = dc->w.hFont;
2296 TextObj = TEXTOBJ_LockText(hFont);
2297 DC_UnlockDc(dc);
2298
2299 if (TextObj == NULL)
2300 {
2301 ExFreePool(SafeBuffer);
2302 SetLastWin32Error(ERROR_INVALID_HANDLE);
2303 return FALSE;
2304 }
2305
2306 FontGDI = ObjToGDI(TextObj->Font, FONT);
2307
2308 face = FontGDI->face;
2309 if (face->charmap == NULL)
2310 {
2311 for (i = 0; i < face->num_charmaps; i++)
2312 {
2313 charmap = face->charmaps[i];
2314 if (charmap->encoding != 0)
2315 {
2316 found = charmap;
2317 break;
2318 }
2319 }
2320
2321 if (!found)
2322 {
2323 DPRINT1("WARNING: Could not find desired charmap!\n");
2324 ExFreePool(SafeBuffer);
2325 SetLastWin32Error(ERROR_INVALID_HANDLE);
2326 return FALSE;
2327 }
2328
2329 IntLockFreeType;
2330 FT_Set_Charmap(face, found);
2331 IntUnLockFreeType;
2332 }
2333
2334 IntLockFreeType;
2335 FT_Set_Pixel_Sizes(face,
2336 TextObj->logfont.lfWidth,
2337 /* FIXME should set character height if neg */
2338 (TextObj->logfont.lfHeight < 0 ?
2339 - TextObj->logfont.lfHeight :
2340 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
2341
2342 for (i = FirstChar; i <= LastChar; i++)
2343 {
2344 glyph_index = FT_Get_Char_Index(face, i);
2345 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2346 SafeBuffer[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
2347 }
2348 IntUnLockFreeType;
2349 TEXTOBJ_UnlockText(TextObj);
2350 MmCopyToCaller(Buffer, SafeBuffer, BufferSize);
2351 ExFreePool(SafeBuffer);
2352 return TRUE;
2353 }
2354
2355 BOOL
2356 STDCALL
2357 NtGdiGetCharWidthFloat(HDC hDC,
2358 UINT FirstChar,
2359 UINT LastChar,
2360 PFLOAT Buffer)
2361 {
2362 UNIMPLEMENTED;
2363 return FALSE;
2364 }
2365
2366 DWORD
2367 STDCALL
2368 NtGdiGetFontLanguageInfo(HDC hDC)
2369 {
2370 UNIMPLEMENTED;
2371 return 0;
2372 }
2373
2374 static
2375 void
2376 FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2377 {
2378 pt->x.value = vec->x >> 6;
2379 pt->x.fract = (vec->x & 0x3f) << 10;
2380 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2381 pt->y.value = vec->y >> 6;
2382 pt->y.fract = (vec->y & 0x3f) << 10;
2383 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2384 return;
2385 }
2386
2387 /*
2388 This function builds an FT_Fixed from a float. It puts the integer part
2389 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2390 It fails if the integer part of the float number is greater than SHORT_MAX.
2391 */
2392 static inline FT_Fixed FT_FixedFromFloat(float f)
2393 {
2394 short value = f;
2395 unsigned short fract = (f - value) * 0xFFFF;
2396 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2397 }
2398
2399 /*
2400 This function builds an FT_Fixed from a FIXED. It simply put f.value
2401 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2402 */
2403 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2404 {
2405 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2406 }
2407
2408 /*
2409 * Based on WineEngGetGlyphOutline
2410 *
2411 */
2412 ULONG
2413 APIENTRY
2414 NtGdiGetGlyphOutline(
2415 IN HDC hdc,
2416 IN WCHAR wch,
2417 IN UINT iFormat,
2418 OUT LPGLYPHMETRICS pgm,
2419 IN ULONG cjBuf,
2420 OUT OPTIONAL PVOID UnsafeBuf,
2421 IN LPMAT2 pmat2,
2422 IN BOOL bIgnoreRotation)
2423 {
2424 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2425 PDC dc;
2426 PTEXTOBJ TextObj;
2427 PFONTGDI FontGDI;
2428 HFONT hFont = 0;
2429 NTSTATUS Status;
2430 GLYPHMETRICS gm;
2431 ULONG Size;
2432 FT_Face ft_face;
2433 FT_UInt glyph_index;
2434 DWORD width, height, pitch, needed = 0;
2435 FT_Bitmap ft_bitmap;
2436 FT_Error error;
2437 INT left, right, top = 0, bottom = 0;
2438 FT_Angle angle = 0;
2439 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2440 FLOAT eM11, widthRatio = 1.0;
2441 FT_Matrix transMat = identityMat;
2442 BOOL needsTransform = FALSE;
2443 INT orientation;
2444 LONG aveWidth;
2445 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
2446 OUTLINETEXTMETRICW *potm;
2447 PVOID pvBuf = NULL;
2448
2449 DPRINT("%p, %d, %08x, %p, %08lx, %p, %p\n", hdc, wch, iFormat, pgm,
2450 cjBuf, UnsafeBuf, pmat2);
2451
2452 dc = DC_LockDc(hdc);
2453 if (!dc)
2454 {
2455 SetLastWin32Error(ERROR_INVALID_HANDLE);
2456 return GDI_ERROR;
2457 }
2458 eM11 = dc->w.xformWorld2Vport.eM11;
2459 hFont = dc->w.hFont;
2460 TextObj = TEXTOBJ_LockText(hFont);
2461 DC_UnlockDc(dc);
2462 if (!TextObj)
2463 {
2464 SetLastWin32Error(ERROR_INVALID_HANDLE);
2465 return GDI_ERROR;
2466 }
2467 FontGDI = ObjToGDI(TextObj->Font, FONT);
2468 ft_face = FontGDI->face;
2469
2470 aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.lfWidth: 0;
2471 orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.lfOrientation: 0;
2472
2473 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2474 potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
2475 if (!potm)
2476 {
2477 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2478 TEXTOBJ_UnlockText(TextObj);
2479 return GDI_ERROR;
2480 }
2481 IntGetOutlineTextMetrics(FontGDI, Size, potm);
2482
2483 IntLockFreeType;
2484
2485 /* During testing, I never saw this used. In here just incase.*/
2486 if (ft_face->charmap == NULL)
2487 {
2488 DPRINT("WARNING: No charmap selected!\n");
2489 DPRINT("This font face has %d charmaps\n", ft_face->num_charmaps);
2490 int n;
2491 FT_CharMap found = 0, charmap;
2492
2493 for (n = 0; n < ft_face->num_charmaps; n++)
2494 {
2495 charmap = ft_face->charmaps[n];
2496 DPRINT("found charmap encoding: %u\n", charmap->encoding);
2497 if (charmap->encoding != 0)
2498 {
2499 found = charmap;
2500 break;
2501 }
2502 }
2503 if (!found)
2504 {
2505 DPRINT1("WARNING: Could not find desired charmap!\n");
2506 }
2507 error = FT_Set_Charmap(ft_face, found);
2508 if (error)
2509 {
2510 DPRINT1("WARNING: Could not set the charmap!\n");
2511 }
2512 }
2513
2514 // FT_Set_Pixel_Sizes(ft_face,
2515 // TextObj->logfont.lfWidth,
2516 /* FIXME should set character height if neg */
2517 // (TextObj->logfont.lfHeight < 0 ? - TextObj->logfont.lfHeight :
2518 // TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
2519
2520 TEXTOBJ_UnlockText(TextObj);
2521
2522 if (iFormat & GGO_GLYPH_INDEX)
2523 {
2524 glyph_index = wch;
2525 iFormat &= ~GGO_GLYPH_INDEX;
2526 }
2527 else glyph_index = FT_Get_Char_Index(ft_face, wch);
2528
2529 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
2530 load_flags |= FT_LOAD_NO_BITMAP;
2531
2532 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
2533 if (error)
2534 {
2535 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
2536 IntUnLockFreeType;
2537 if (potm) ExFreePool(potm);
2538 return GDI_ERROR;
2539 }
2540 IntUnLockFreeType;
2541
2542 if (aveWidth && potm)
2543 {
2544 widthRatio = (FLOAT)aveWidth * eM11 /
2545 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
2546 }
2547
2548 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2549 right = (INT)((ft_face->glyph->metrics.horiBearingX +
2550 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2551
2552 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2553 lsb = left >> 6;
2554 bbx = (right - left) >> 6;
2555
2556 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
2557
2558 IntLockFreeType;
2559
2560 /* Scaling transform */
2561 if (aveWidth)
2562 {
2563 FT_Matrix scaleMat;
2564 DPRINT("Scaling Trans!\n");
2565 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2566 scaleMat.xy = 0;
2567 scaleMat.yx = 0;
2568 scaleMat.yy = (1 << 16);
2569 FT_Matrix_Multiply(&scaleMat, &transMat);
2570 needsTransform = TRUE;
2571 }
2572
2573 /* Slant transform */
2574 if (potm->otmTextMetrics.tmItalic)
2575 {
2576 FT_Matrix slantMat;
2577 DPRINT("Slant Trans!\n");
2578 slantMat.xx = (1 << 16);
2579 slantMat.xy = ((1 << 16) >> 2);
2580 slantMat.yx = 0;
2581 slantMat.yy = (1 << 16);
2582 FT_Matrix_Multiply(&slantMat, &transMat);
2583 needsTransform = TRUE;
2584 }
2585
2586 /* Rotation transform */
2587 if (orientation)
2588 {
2589 FT_Matrix rotationMat;
2590 FT_Vector vecAngle;
2591 DPRINT("Rotation Trans!\n");
2592 angle = FT_FixedFromFloat((float)orientation / 10.0);
2593 FT_Vector_Unit(&vecAngle, angle);
2594 rotationMat.xx = vecAngle.x;
2595 rotationMat.xy = -vecAngle.y;
2596 rotationMat.yx = -rotationMat.xy;
2597 rotationMat.yy = rotationMat.xx;
2598 FT_Matrix_Multiply(&rotationMat, &transMat);
2599 needsTransform = TRUE;
2600 }
2601
2602 /* Extra transformation specified by caller */
2603 if (pmat2)
2604 {
2605 FT_Matrix extraMat;
2606 DPRINT("MAT2 Matrix Trans!\n");
2607 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
2608 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
2609 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
2610 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
2611 FT_Matrix_Multiply(&extraMat, &transMat);
2612 needsTransform = TRUE;
2613 }
2614
2615 if (potm) ExFreePool(potm); /* It looks like we are finished with potm ATM.*/
2616
2617 if (!needsTransform)
2618 {
2619 DPRINT("No Need to be Transformed!\n");
2620 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2621 bottom = (ft_face->glyph->metrics.horiBearingY -
2622 ft_face->glyph->metrics.height) & -64;
2623 gm.gmCellIncX = adv;
2624 gm.gmCellIncY = 0;
2625 }
2626 else
2627 {
2628 INT xc, yc;
2629 FT_Vector vec;
2630 for(xc = 0; xc < 2; xc++)
2631 {
2632 for(yc = 0; yc < 2; yc++)
2633 {
2634 vec.x = (ft_face->glyph->metrics.horiBearingX +
2635 xc * ft_face->glyph->metrics.width);
2636 vec.y = ft_face->glyph->metrics.horiBearingY -
2637 yc * ft_face->glyph->metrics.height;
2638 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
2639 FT_Vector_Transform(&vec, &transMat);
2640 if(xc == 0 && yc == 0)
2641 {
2642 left = right = vec.x;
2643 top = bottom = vec.y;
2644 }
2645 else
2646 {
2647 if(vec.x < left) left = vec.x;
2648 else if(vec.x > right) right = vec.x;
2649 if(vec.y < bottom) bottom = vec.y;
2650 else if(vec.y > top) top = vec.y;
2651 }
2652 }
2653 }
2654 left = left & -64;
2655 right = (right + 63) & -64;
2656 bottom = bottom & -64;
2657 top = (top + 63) & -64;
2658
2659 DPRINT("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2660 vec.x = ft_face->glyph->metrics.horiAdvance;
2661 vec.y = 0;
2662 FT_Vector_Transform(&vec, &transMat);
2663 gm.gmCellIncX = (vec.x+63) >> 6;
2664 gm.gmCellIncY = -((vec.y+63) >> 6);
2665 }
2666 gm.gmBlackBoxX = (right - left) >> 6;
2667 gm.gmBlackBoxY = (top - bottom) >> 6;
2668 gm.gmptGlyphOrigin.x = left >> 6;
2669 gm.gmptGlyphOrigin.y = top >> 6;
2670
2671 DPRINT("CX %d CY %d BBX %d BBY %d GOX %d GOY %d\n",
2672 gm.gmCellIncX, gm.gmCellIncY,
2673 gm.gmBlackBoxX, gm.gmBlackBoxY,
2674 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
2675
2676 IntUnLockFreeType;
2677
2678 if (pgm)
2679 {
2680 Status = MmCopyToCaller(pgm, &gm, sizeof(GLYPHMETRICS));
2681 if (! NT_SUCCESS(Status))
2682 {
2683 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2684 return GDI_ERROR;
2685 }
2686 DPRINT("Copied GLYPHMETRICS to User!\n");
2687 }
2688
2689 if (iFormat == GGO_METRICS)
2690 {
2691 DPRINT("GGO_METRICS Exit!\n");
2692 return 1; /* FIXME */
2693 }
2694
2695 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
2696 {
2697 DPRINT1("loaded a bitmap\n");
2698 return GDI_ERROR;
2699 }
2700
2701 if (UnsafeBuf && cjBuf)
2702 {
2703 pvBuf = ExAllocatePoolWithTag(PagedPool, cjBuf, TAG_GDITEXT);
2704 if (pvBuf == NULL)
2705 {
2706 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2707 return GDI_ERROR;
2708 }
2709 RtlZeroMemory(pvBuf, cjBuf);
2710 }
2711
2712
2713 switch(iFormat)
2714 {
2715 case GGO_BITMAP:
2716 width = gm.gmBlackBoxX;
2717 height = gm.gmBlackBoxY;
2718 pitch = ((width + 31) >> 5) << 2;
2719 needed = pitch * height;
2720
2721 if(!pvBuf || !cjBuf) break;
2722
2723 switch(ft_face->glyph->format)
2724 {
2725 case ft_glyph_format_bitmap:
2726 {
2727 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
2728 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2729 INT h = ft_face->glyph->bitmap.rows;
2730 while(h--)
2731 {
2732 RtlCopyMemory(dst, src, w);
2733 src += ft_face->glyph->bitmap.pitch;
2734 dst += pitch;
2735 }
2736 break;
2737 }
2738
2739 case ft_glyph_format_outline:
2740 ft_bitmap.width = width;
2741 ft_bitmap.rows = height;
2742 ft_bitmap.pitch = pitch;
2743 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2744 ft_bitmap.buffer = pvBuf;
2745
2746 IntLockFreeType;
2747 if(needsTransform)
2748 {
2749 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2750 }
2751 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2752 /* Note: FreeType will only set 'black' bits for us. */
2753 RtlZeroMemory(pvBuf, needed);
2754 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2755 IntUnLockFreeType;
2756 break;
2757
2758 default:
2759 DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
2760 if(pvBuf) ExFreePool(pvBuf);
2761 return GDI_ERROR;
2762 }
2763 break;
2764
2765 case GGO_GRAY2_BITMAP:
2766 case GGO_GRAY4_BITMAP:
2767 case GGO_GRAY8_BITMAP:
2768 {
2769 unsigned int mult, row, col;
2770 BYTE *start, *ptr;
2771
2772 width = gm.gmBlackBoxX;
2773 height = gm.gmBlackBoxY;
2774 pitch = (width + 3) / 4 * 4;
2775 needed = pitch * height;
2776
2777 if(!pvBuf || !cjBuf) break;
2778
2779 ft_bitmap.width = width;
2780 ft_bitmap.rows = height;
2781 ft_bitmap.pitch = pitch;
2782 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2783 ft_bitmap.buffer = pvBuf;
2784
2785 IntLockFreeType;
2786 if(needsTransform)
2787 {
2788 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2789 }
2790 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2791 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
2792 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2793 IntUnLockFreeType;
2794
2795 if(iFormat == GGO_GRAY2_BITMAP)
2796 mult = 4;
2797 else if(iFormat == GGO_GRAY4_BITMAP)
2798 mult = 16;
2799 else if(iFormat == GGO_GRAY8_BITMAP)
2800 mult = 64;
2801 else
2802 {
2803 ASSERT(0);
2804 break;
2805 }
2806
2807 start = pvBuf;
2808 for(row = 0; row < height; row++)
2809 {
2810 ptr = start;
2811 for(col = 0; col < width; col++, ptr++)
2812 {
2813 *ptr = (((int)*ptr) * mult + 128) / 256;
2814 }
2815 start += pitch;
2816 }
2817 break;
2818 }
2819
2820 case GGO_NATIVE:
2821 {
2822 int contour, point = 0, first_pt;
2823 FT_Outline *outline = &ft_face->glyph->outline;
2824 TTPOLYGONHEADER *pph;
2825 TTPOLYCURVE *ppc;
2826 DWORD pph_start, cpfx, type;
2827
2828 if(cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
2829
2830 IntLockFreeType;
2831 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
2832
2833 for(contour = 0; contour < outline->n_contours; contour++)
2834 {
2835 pph_start = needed;
2836 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
2837 first_pt = point;
2838 if(pvBuf)
2839 {
2840 pph->dwType = TT_POLYGON_TYPE;
2841 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2842 }
2843 needed += sizeof(*pph);
2844 point++;
2845 while(point <= outline->contours[contour])
2846 {
2847 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
2848 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2849 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2850 cpfx = 0;
2851 do
2852 {
2853 if(pvBuf)
2854 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2855 cpfx++;
2856 point++;
2857 } while(point <= outline->contours[contour] &&
2858 (outline->tags[point] & FT_Curve_Tag_On) ==
2859 (outline->tags[point-1] & FT_Curve_Tag_On));
2860
2861 /* At the end of a contour Windows adds the start point, but
2862 only for Beziers */
2863 if(point > outline->contours[contour] &&
2864 !(outline->tags[point-1] & FT_Curve_Tag_On))
2865 {
2866 if(pvBuf)
2867 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2868 cpfx++;
2869 }
2870 else if(point <= outline->contours[contour] &&
2871 outline->tags[point] & FT_Curve_Tag_On)
2872 {
2873 /* add closing pt for bezier */
2874 if(pvBuf)
2875 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2876 cpfx++;
2877 point++;
2878 }
2879 if(pvBuf)
2880 {
2881 ppc->wType = type;
2882 ppc->cpfx = cpfx;
2883 }
2884 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2885 }
2886 if(pvBuf) pph->cb = needed - pph_start;
2887 }
2888 IntUnLockFreeType;
2889 break;
2890 }
2891 case GGO_BEZIER:
2892 {
2893 /* Convert the quadratic Beziers to cubic Beziers.
2894 The parametric eqn for a cubic Bezier is, from PLRM:
2895 r(t) = at^3 + bt^2 + ct + r0
2896 with the control points:
2897 r1 = r0 + c/3
2898 r2 = r1 + (c + b)/3
2899 r3 = r0 + c + b + a
2900
2901 A quadratic Beizer has the form:
2902 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2903
2904 So equating powers of t leads to:
2905 r1 = 2/3 p1 + 1/3 p0
2906 r2 = 2/3 p1 + 1/3 p2
2907 and of course r0 = p0, r3 = p2
2908 */
2909
2910 int contour, point = 0, first_pt;
2911 FT_Outline *outline = &ft_face->glyph->outline;
2912 TTPOLYGONHEADER *pph;
2913 TTPOLYCURVE *ppc;
2914 DWORD pph_start, cpfx, type;
2915 FT_Vector cubic_control[4];
2916 if(cjBuf == 0) pvBuf = NULL;
2917
2918 if (needsTransform && pvBuf)
2919 {
2920 IntLockFreeType;
2921 FT_Outline_Transform(outline, &transMat);
2922 IntUnLockFreeType;
2923 }
2924
2925 for(contour = 0; contour < outline->n_contours; contour++)
2926 {
2927 pph_start = needed;
2928 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
2929 first_pt = point;
2930 if(pvBuf)
2931 {
2932 pph->dwType = TT_POLYGON_TYPE;
2933 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2934 }
2935 needed += sizeof(*pph);
2936 point++;
2937 while(point <= outline->contours[contour])
2938 {
2939 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
2940 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2941 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2942 cpfx = 0;
2943 do
2944 {
2945 if(type == TT_PRIM_LINE)
2946 {
2947 if(pvBuf)
2948 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2949 cpfx++;
2950 point++;
2951 }
2952 else
2953 {
2954 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2955 so cpfx = 3n */
2956
2957 /* FIXME: Possible optimization in endpoint calculation
2958 if there are two consecutive curves */
2959 cubic_control[0] = outline->points[point-1];
2960 if(!(outline->tags[point-1] & FT_Curve_Tag_On))
2961 {
2962 cubic_control[0].x += outline->points[point].x + 1;
2963 cubic_control[0].y += outline->points[point].y + 1;
2964 cubic_control[0].x >>= 1;
2965 cubic_control[0].y >>= 1;
2966 }
2967 if(point+1 > outline->contours[contour])
2968 cubic_control[3] = outline->points[first_pt];
2969 else
2970 {
2971 cubic_control[3] = outline->points[point+1];
2972 if(!(outline->tags[point+1] & FT_Curve_Tag_On))
2973 {
2974 cubic_control[3].x += outline->points[point].x + 1;
2975 cubic_control[3].y += outline->points[point].y + 1;
2976 cubic_control[3].x >>= 1;
2977 cubic_control[3].y >>= 1;
2978 }
2979 }
2980 /* r1 = 1/3 p0 + 2/3 p1
2981 r2 = 1/3 p2 + 2/3 p1 */
2982 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
2983 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
2984 cubic_control[2] = cubic_control[1];
2985 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
2986 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
2987 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
2988 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
2989 if(pvBuf)
2990 {
2991 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
2992 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
2993 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
2994 }
2995 cpfx += 3;
2996 point++;
2997 }
2998 }
2999 while(point <= outline->contours[contour] &&
3000 (outline->tags[point] & FT_Curve_Tag_On) ==
3001 (outline->tags[point-1] & FT_Curve_Tag_On));
3002 /* At the end of a contour Windows adds the start point,
3003 but only for Beziers and we've already done that.
3004 */
3005 if(point <= outline->contours[contour] &&
3006 outline->tags[point] & FT_Curve_Tag_On)
3007 {
3008 /* This is the closing pt of a bezier, but we've already
3009 added it, so just inc point and carry on */
3010 point++;
3011 }
3012 if(pvBuf)
3013 {
3014 ppc->wType = type;
3015 ppc->cpfx = cpfx;
3016 }
3017 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3018 }
3019 if(pvBuf) pph->cb = needed - pph_start;
3020 }
3021 break;
3022 }
3023
3024 default:
3025 DPRINT1("Unsupported format %d\n", iFormat);
3026 if(pvBuf) ExFreePool(pvBuf);
3027 return GDI_ERROR;
3028 }
3029
3030 if (pvBuf)
3031 {
3032 Status = MmCopyToCaller(UnsafeBuf, pvBuf, cjBuf);
3033 if (! NT_SUCCESS(Status))
3034 {
3035 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3036 ExFreePool(pvBuf);
3037 return GDI_ERROR;
3038 }
3039 DPRINT("NtGdiGetGlyphOutline K -> U worked!\n");
3040 ExFreePool(pvBuf);
3041 }
3042
3043 DPRINT("NtGdiGetGlyphOutline END and needed %d\n", needed);
3044 return needed;
3045 }
3046
3047 DWORD
3048 STDCALL
3049 NtGdiGetKerningPairs(HDC hDC,
3050 DWORD NumPairs,
3051 LPKERNINGPAIR krnpair)
3052 {
3053 UNIMPLEMENTED;
3054 return 0;
3055 }
3056
3057 /*
3058 From "Undocumented Windows 2000 Secrets" Appendix B, Table B-2, page
3059 472, this is NtGdiGetOutlineTextMetricsInternalW.
3060 */
3061 UINT
3062 STDCALL
3063 NtGdiGetOutlineTextMetrics(HDC hDC,
3064 UINT Data,
3065 LPOUTLINETEXTMETRICW otm)
3066 {
3067 PDC dc;
3068 PTEXTOBJ TextObj;
3069 PFONTGDI FontGDI;
3070 HFONT hFont = 0;
3071 ULONG Size;
3072 OUTLINETEXTMETRICW *potm;
3073 NTSTATUS Status;
3074
3075 dc = DC_LockDc(hDC);
3076 if (dc == NULL)
3077 {
3078 SetLastWin32Error(ERROR_INVALID_HANDLE);
3079 return 0;
3080 }
3081 hFont = dc->w.hFont;
3082 TextObj = TEXTOBJ_LockText(hFont);
3083 DC_UnlockDc(dc);
3084 if (TextObj == NULL)
3085 {
3086 SetLastWin32Error(ERROR_INVALID_HANDLE);
3087 return 0;
3088 }
3089 FontGDI = ObjToGDI(TextObj->Font, FONT);
3090 TEXTOBJ_UnlockText(TextObj);
3091 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3092 if (!otm) return Size;
3093 if (Size > Data)
3094 {
3095 SetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
3096 return 0;
3097 }
3098 potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
3099 if (NULL == potm)
3100 {
3101 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3102 return 0;
3103 }
3104 IntGetOutlineTextMetrics(FontGDI, Size, potm);
3105 if (otm)
3106 {
3107 Status = MmCopyToCaller(otm, potm, Size);
3108 if (! NT_SUCCESS(Status))
3109 {
3110 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3111 ExFreePool(potm);
3112 return 0;
3113 }
3114 }
3115 ExFreePool(potm);
3116 return Size;
3117 }
3118
3119
3120 BOOL
3121 APIENTRY
3122 NtGdiGetRasterizerCaps(
3123 OUT LPRASTERIZER_STATUS praststat,
3124 IN ULONG cjBytes)
3125 {
3126 UNIMPLEMENTED;
3127 return FALSE;
3128 }
3129
3130
3131 /*
3132 Based on "Undocumented W2k Secrets", Table B-2, page 473.
3133 This function does not exist. See note in gdi32/objects/text.c
3134 GetTextCharset. This should be moved to include/win32k/ntgdibad.h.
3135 */
3136 UINT
3137 STDCALL
3138 NtGdiGetTextCharset(HDC hDC)
3139 {
3140 UNIMPLEMENTED;
3141 return 0;
3142 }
3143
3144 INT
3145 APIENTRY
3146 NtGdiGetTextCharsetInfo(
3147 IN HDC hdc,
3148 OUT OPTIONAL LPFONTSIGNATURE lpSig,
3149 IN DWORD dwFlags)
3150 {
3151 PDC Dc;
3152 UINT Ret = DEFAULT_CHARSET, i = 0, fs_fsCsb0 = 0;
3153 HFONT hFont;
3154 PTEXTOBJ TextObj;
3155 PFONTGDI FontGdi;
3156 FONTSIGNATURE fs;
3157 TT_OS2 *pOS2;
3158 FT_Face Face;
3159 NTSTATUS Status;
3160
3161 Dc = DC_LockDc(hdc);
3162 if (!Dc)
3163 {
3164 SetLastWin32Error(ERROR_INVALID_HANDLE);
3165 return Ret;
3166 }
3167 hFont = Dc->w.hFont;
3168 TextObj = TEXTOBJ_LockText(hFont);
3169 DC_UnlockDc( Dc );
3170 if ( TextObj == NULL)
3171 {
3172 SetLastWin32Error(ERROR_INVALID_HANDLE);
3173 return Ret;
3174 }
3175 FontGdi = ObjToGDI(TextObj->Font, FONT);
3176 Face = FontGdi->face;
3177 TEXTOBJ_UnlockText(TextObj);
3178 IntLockFreeType;
3179 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3180 IntUnLockFreeType;
3181 memset(&fs, 0, sizeof(FONTSIGNATURE));
3182 if (NULL != pOS2)
3183 {
3184 fs.fsCsb[0] = pOS2->ulCodePageRange1;
3185 fs.fsCsb[1] = pOS2->ulCodePageRange2;
3186 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3187 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3188 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3189 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3190 fs_fsCsb0 = pOS2->ulCodePageRange1;
3191 if (pOS2->version == 0)
3192 {
3193 FT_UInt dummy;
3194
3195 if(FT_Get_First_Char( Face, &dummy ) < 0x100)
3196 fs_fsCsb0 |= 1;
3197 else
3198 fs_fsCsb0 |= 1L << 31;
3199 }
3200 }
3201 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
3202 if (lpSig)
3203 {
3204 Status = MmCopyToCaller(lpSig, &fs, sizeof(FONTSIGNATURE));
3205 if (! NT_SUCCESS(Status))
3206 {
3207 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3208 return Ret;
3209 }
3210 }
3211 if (0 == fs_fsCsb0)
3212 { /* let's see if we can find any interesting cmaps */
3213 for (i = 0; i < Face->num_charmaps; i++)
3214 {
3215 switch (Face->charmaps[i]->encoding)
3216 {
3217 case ft_encoding_unicode:
3218 case ft_encoding_apple_roman:
3219 fs_fsCsb0 |= 1;
3220 break;
3221 case ft_encoding_symbol:
3222 fs_fsCsb0 |= 1L << 31;
3223 break;
3224 default:
3225 break;
3226 }
3227 }
3228 }
3229 while (0 == (fs_fsCsb0 >> i & 0x0001) && i < MAXTCIINDEX)
3230 {
3231 i++;
3232 }
3233 Ret = FontTci[i].ciCharset;
3234 DPRINT("CharSet %d\n",Ret);
3235 return Ret;
3236 }
3237
3238 static BOOL
3239 FASTCALL
3240 TextIntGetTextExtentPoint(PDC dc,
3241 PTEXTOBJ TextObj,
3242 LPCWSTR String,
3243 int Count,
3244 int MaxExtent,
3245 LPINT Fit,
3246 LPINT Dx,
3247 LPSIZE Size)
3248 {
3249 PFONTGDI FontGDI;
3250 FT_Face face;
3251 FT_GlyphSlot glyph;
3252 INT error, n, glyph_index, i, previous;
3253 ULONGLONG TotalWidth = 0;
3254 FT_CharMap charmap, found = NULL;
3255 BOOL use_kerning;
3256
3257 FontGDI = ObjToGDI(TextObj->Font, FONT);
3258
3259 face = FontGDI->face;
3260 if (NULL != Fit)
3261 {
3262 *Fit = 0;
3263 }
3264
3265 if (face->charmap == NULL)
3266 {
3267 DPRINT("WARNING: No charmap selected!\n");
3268 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3269
3270 for (n = 0; n < face->num_charmaps; n++)
3271 {
3272 charmap = face->charmaps[n];
3273 DPRINT("found charmap encoding: %u\n", charmap->encoding);
3274 if (charmap->encoding != 0)
3275 {
3276 found = charmap;
3277 break;
3278 }
3279 }
3280
3281 if (! found)
3282 {
3283 DPRINT1("WARNING: Could not find desired charmap!\n");
3284 }
3285
3286 IntLockFreeType;
3287 error = FT_Set_Charmap(face, found);
3288 IntUnLockFreeType;
3289 if (error)
3290 {
3291 DPRINT1("WARNING: Could not set the charmap!\n");
3292 }
3293 }
3294
3295 IntLockFreeType;
3296 error = FT_Set_Pixel_Sizes(face,
3297 TextObj->logfont.lfWidth,
3298 /* FIXME should set character height if neg */
3299 (TextObj->logfont.lfHeight < 0 ?
3300 - TextObj->logfont.lfHeight :
3301 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
3302 IntUnLockFreeType;
3303 if (error)
3304 {
3305 DPRINT1("Error in setting pixel sizes: %u\n", error);
3306 }
3307
3308 use_kerning = FT_HAS_KERNING(face);
3309 previous = 0;
3310
3311 for (i = 0; i < Count; i++)
3312 {
3313 IntLockFreeType;
3314 glyph_index = FT_Get_Char_Index(face, *String);
3315 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3316 IntUnLockFreeType;
3317 if (error)
3318 {
3319 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3320 }
3321 glyph = face->glyph;
3322
3323 /* retrieve kerning distance */
3324 if (use_kerning && previous && glyph_index)
3325 {
3326 FT_Vector delta;
3327 IntLockFreeType;
3328 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3329 IntUnLockFreeType;
3330 TotalWidth += delta.x;
3331 }
3332
3333 TotalWidth += glyph->advance.x;
3334
3335 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
3336 {
3337 *Fit = i + 1;
3338 }
3339 if (NULL != Dx)
3340 {
3341 Dx[i] = (TotalWidth + 32) >> 6;
3342 }
3343
3344 previous = glyph_index;
3345 String++;
3346 }
3347
3348 Size->cx = (TotalWidth + 32) >> 6;
3349 Size->cy = (TextObj->logfont.lfHeight < 0 ? - TextObj->logfont.lfHeight : TextObj->logfont.lfHeight);
3350 Size->cy = EngMulDiv(Size->cy, IntGdiGetDeviceCaps(dc, LOGPIXELSY), 72);
3351
3352 return TRUE;
3353 }
3354
3355 BOOL
3356 STDCALL
3357 NtGdiGetTextExtentExPoint(HDC hDC,
3358 LPCWSTR UnsafeString,
3359 int Count,
3360 int MaxExtent,
3361 LPINT UnsafeFit,
3362 LPINT UnsafeDx,
3363 LPSIZE UnsafeSize)
3364 {
3365 PDC dc;
3366 LPWSTR String;
3367 SIZE Size;
3368 NTSTATUS Status;
3369 BOOLEAN Result;
3370 INT Fit;
3371 LPINT Dx;
3372 PTEXTOBJ TextObj;
3373
3374 if (Count < 0)
3375 {
3376 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3377 return FALSE;
3378 }
3379 if (0 == Count)
3380 {
3381 Size.cx = 0;
3382 Size.cy = 0;
3383 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
3384 if (! NT_SUCCESS(Status))
3385 {
3386 SetLastNtError(Status);
3387 return FALSE;
3388 }
3389 return TRUE;
3390 }
3391
3392 String = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), TAG_GDITEXT);
3393 if (NULL == String)
3394 {
3395 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3396 return FALSE;
3397 }
3398
3399 if (NULL != UnsafeDx)
3400 {
3401 Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
3402 if (NULL == Dx)
3403 {
3404 ExFreePool(String);
3405 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3406 return FALSE;
3407 }
3408 }
3409 else
3410 {
3411 Dx = NULL;
3412 }
3413
3414 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
3415 if (! NT_SUCCESS(Status))
3416 {
3417 if (NULL != Dx)
3418 {
3419 ExFreePool(Dx);
3420 }
3421 ExFreePool(String);
3422 SetLastNtError(Status);
3423 return FALSE;
3424 }
3425
3426 dc = DC_LockDc(hDC);
3427 if (NULL == dc)
3428 {
3429 if (NULL != Dx)
3430 {
3431 ExFreePool(Dx);
3432 }
3433 ExFreePool(String);
3434 SetLastWin32Error(ERROR_INVALID_HANDLE);
3435 return FALSE;
3436 }
3437 TextObj = TEXTOBJ_LockText(dc->w.hFont);
3438 if ( TextObj )
3439 {
3440 Result = TextIntGetTextExtentPoint(dc, TextObj, String, Count, MaxExtent,
3441 NULL == UnsafeFit ? NULL : &Fit, Dx, &Size);
3442 }
3443 else
3444 Result = FALSE;
3445 TEXTOBJ_UnlockText(TextObj);
3446 DC_UnlockDc(dc);
3447
3448 ExFreePool(String);
3449 if (! Result)
3450 {
3451 if (NULL != Dx)
3452 {
3453 ExFreePool(Dx);
3454 }
3455 return FALSE;
3456 }
3457
3458 if (NULL != UnsafeFit)
3459 {
3460 Status = MmCopyToCaller(UnsafeFit, &Fit, sizeof(INT));
3461 if (! NT_SUCCESS(Status))
3462 {
3463 if (NULL != Dx)
3464 {
3465 ExFreePool(Dx);
3466 }
3467 SetLastNtError(Status);
3468 return FALSE;
3469 }
3470 }
3471
3472 if (NULL != UnsafeDx)
3473 {
3474 Status = MmCopyToCaller(UnsafeDx, Dx, Count * sizeof(INT));
3475 if (! NT_SUCCESS(Status))
3476 {
3477 if (NULL != Dx)
3478 {
3479 ExFreePool(Dx);
3480 }
3481 SetLastNtError(Status);
3482 return FALSE;
3483 }
3484 }
3485 if (NULL != Dx)
3486 {
3487 ExFreePool(Dx);
3488 }
3489
3490 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
3491 if (! NT_SUCCESS(Status))
3492 {
3493 SetLastNtError(Status);
3494 return FALSE;
3495 }
3496
3497 return TRUE;
3498 }
3499
3500 BOOL
3501 STDCALL
3502 NtGdiGetTextExtent(HDC hdc,
3503 LPWSTR lpwsz,
3504 INT cwc,
3505 LPSIZE psize,
3506 UINT flOpts)
3507 {
3508 return NtGdiGetTextExtentExPoint(hdc, lpwsz, cwc, 0, NULL, NULL, psize);
3509 }
3510
3511 BOOL
3512 STDCALL
3513 NtGdiGetTextExtentPoint32(HDC hDC,
3514 LPCWSTR UnsafeString,
3515 int Count,
3516 LPSIZE UnsafeSize)
3517 {
3518 PDC dc;
3519 LPWSTR String;
3520 SIZE Size;
3521 NTSTATUS Status;
3522 BOOLEAN Result;
3523 PTEXTOBJ TextObj;
3524
3525 if (Count < 0)
3526 {
3527 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3528 return FALSE;
3529 }
3530 if (0 == Count)
3531 {
3532 Size.cx = 0;
3533 Size.cy = 0;
3534 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
3535 if (! NT_SUCCESS(Status))
3536 {
3537 SetLastNtError(Status);
3538 return FALSE;
3539 }
3540 return TRUE;
3541 }
3542
3543 String = ExAllocatePool(PagedPool, Count * sizeof(WCHAR));
3544 if (NULL == String)
3545 {
3546 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3547 return FALSE;
3548 }
3549
3550 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
3551 if (! NT_SUCCESS(Status))
3552 {
3553 ExFreePool(String);
3554 SetLastNtError(Status);
3555 return FALSE;
3556 }
3557
3558 dc = DC_LockDc(hDC);
3559 if (NULL == dc)
3560 {
3561 ExFreePool(String);
3562 SetLastWin32Error(ERROR_INVALID_HANDLE);
3563 return FALSE;
3564 }
3565 TextObj = TEXTOBJ_LockText(dc->w.hFont);
3566 if ( TextObj != NULL )
3567 {
3568 Result = TextIntGetTextExtentPoint (
3569 dc, TextObj, String, Count, 0, NULL, NULL, &Size);
3570 TEXTOBJ_UnlockText(TextObj);
3571 }
3572 else
3573 Result = FALSE;
3574 DC_UnlockDc(dc);
3575
3576 ExFreePool(String);
3577 if (! Result)
3578 {
3579 return FALSE;
3580 }
3581
3582 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
3583 if (! NT_SUCCESS(Status))
3584 {
3585 SetLastNtError(Status);
3586 return FALSE;
3587 }
3588
3589 return TRUE;
3590 }
3591
3592 INT STDCALL
3593 NtGdiGetTextFace(HDC hDC, INT Count, LPWSTR FaceName)
3594 {
3595 PDC Dc;
3596 HFONT hFont;
3597 PTEXTOBJ TextObj;
3598 NTSTATUS Status;
3599
3600 Dc = DC_LockDc(hDC);
3601 if (Dc == NULL)
3602 {
3603 SetLastWin32Error(ERROR_INVALID_HANDLE);
3604 return FALSE;
3605 }
3606 hFont = Dc->w.hFont;
3607 DC_UnlockDc(Dc);
3608
3609 TextObj = TEXTOBJ_LockText(hFont);
3610 ASSERT(TextObj != NULL);
3611 Count = min(Count, wcslen(TextObj->logfont.lfFaceName));
3612 Status = MmCopyToCaller(FaceName, TextObj->logfont.lfFaceName, Count * sizeof(WCHAR));
3613 TEXTOBJ_UnlockText(TextObj);
3614 if (!NT_SUCCESS(Status))
3615 {
3616 SetLastNtError(Status);
3617 return 0;
3618 }
3619
3620 return Count;
3621 }
3622
3623 BOOL
3624 STDCALL
3625 NtGdiGetTextMetrics(HDC hDC,
3626 LPTEXTMETRICW tm)
3627 {
3628 PDC dc;
3629 PTEXTOBJ TextObj;
3630 PFONTGDI FontGDI;
3631 NTSTATUS Status = STATUS_SUCCESS;
3632 TEXTMETRICW SafeTm;
3633 FT_Face Face;
3634 TT_OS2 *pOS2;
3635 TT_HoriHeader *pHori;
3636 ULONG Error;
3637
3638 if (NULL == tm)
3639 {
3640 SetLastWin32Error(STATUS_INVALID_PARAMETER);
3641 return FALSE;
3642 }
3643
3644 if(!(dc = DC_LockDc(hDC)))
3645 {
3646 SetLastWin32Error(ERROR_INVALID_HANDLE);
3647 return FALSE;
3648 }
3649
3650 TextObj = TEXTOBJ_LockText(dc->w.hFont);
3651 if (NULL != TextObj)
3652 {
3653 FontGDI = ObjToGDI(TextObj->Font, FONT);
3654
3655 Face = FontGDI->face;
3656 IntLockFreeType;
3657 Error = FT_Set_Pixel_Sizes(Face,
3658 TextObj->logfont.lfWidth,
3659 /* FIXME should set character height if neg */
3660 (TextObj->logfont.lfHeight < 0 ?
3661 - TextObj->logfont.lfHeight :
3662 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
3663 IntUnLockFreeType;
3664 if (0 != Error)
3665 {
3666 DPRINT1("Error in setting pixel sizes: %u\n", Error);
3667 Status = STATUS_UNSUCCESSFUL;
3668 }
3669 else
3670 {
3671 memcpy(&SafeTm, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
3672
3673 Status = STATUS_SUCCESS;
3674 IntLockFreeType;
3675 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
3676 if (NULL == pOS2)
3677 {
3678 DPRINT1("Can't find OS/2 table - not TT font?\n");
3679 Status = STATUS_INTERNAL_ERROR;
3680 }
3681
3682 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
3683 if (NULL == pHori)
3684 {
3685 DPRINT1("Can't find HHEA table - not TT font?\n");
3686 Status = STATUS_INTERNAL_ERROR;
3687 }
3688
3689 IntUnLockFreeType;
3690
3691 if (NT_SUCCESS(Status))
3692 {
3693 FillTM(&SafeTm, FontGDI->face, pOS2, pHori);
3694 Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
3695 }
3696 }
3697 TEXTOBJ_UnlockText(TextObj);
3698 }
3699 else
3700 {
3701 Status = STATUS_INVALID_HANDLE;
3702 }
3703 DC_UnlockDc(dc);
3704
3705 if(!NT_SUCCESS(Status))
3706 {
3707 SetLastNtError(Status);
3708 return FALSE;
3709 }
3710
3711 return TRUE;
3712 }
3713
3714 BOOL
3715 STDCALL
3716 NtGdiPolyTextOut(HDC hDC,
3717 CONST LPPOLYTEXTW txt,
3718 int Count)
3719 {
3720 UNIMPLEMENTED;
3721 return FALSE;
3722 }
3723
3724 BOOL
3725 STDCALL
3726 NtGdiRemoveFontResource(LPCWSTR FileName)
3727 {
3728 DPRINT1("NtGdiRemoveFontResource is UNIMPLEMENTED\n");
3729 return FALSE;
3730 }
3731
3732 DWORD
3733 STDCALL
3734 NtGdiSetMapperFlags(HDC hDC,
3735 DWORD Flag)
3736 {
3737 UNIMPLEMENTED;
3738 return 0;
3739 }
3740
3741 UINT
3742 STDCALL
3743 NtGdiSetTextAlign(HDC hDC,
3744 UINT Mode)
3745 {
3746 UINT prevAlign;
3747 DC *dc;
3748
3749 dc = DC_LockDc(hDC);
3750 if (!dc)
3751 {
3752 SetLastWin32Error(ERROR_INVALID_HANDLE);
3753 return GDI_ERROR;
3754 }
3755 prevAlign = dc->w.textAlign;
3756 dc->w.textAlign = Mode;
3757 DC_UnlockDc( dc );
3758 return prevAlign;
3759 }
3760
3761 COLORREF
3762 STDCALL
3763 NtGdiSetTextColor(HDC hDC,
3764 COLORREF color)
3765 {
3766 COLORREF oldColor;
3767 PDC dc = DC_LockDc(hDC);
3768 HBRUSH hBrush;
3769
3770 if (!dc)
3771 {
3772 SetLastWin32Error(ERROR_INVALID_HANDLE);
3773 return CLR_INVALID;
3774 }
3775
3776 oldColor = dc->w.textColor;
3777 dc->w.textColor = color;
3778 hBrush = dc->w.hBrush;
3779 DC_UnlockDc( dc );
3780 NtGdiSelectObject(hDC, hBrush);
3781 return oldColor;
3782 }
3783
3784 BOOL
3785 STDCALL
3786 NtGdiSetTextJustification(HDC hDC,
3787 int BreakExtra,
3788 int BreakCount)
3789 {
3790 UNIMPLEMENTED;
3791 return FALSE;
3792 }
3793
3794 BOOL STDCALL
3795 NtGdiTextOut(
3796 HDC hDC,
3797 INT XStart,
3798 INT YStart,
3799 LPCWSTR String,
3800 INT Count)
3801 {
3802 return NtGdiExtTextOut(hDC, XStart, YStart, 0, NULL, String, Count, NULL);
3803 }
3804
3805 DWORD STDCALL
3806 NtGdiGetFontData(
3807 HDC hDC,
3808 DWORD Table,
3809 DWORD Offset,
3810 LPVOID Buffer,
3811 DWORD Size)
3812 {
3813 PDC Dc;
3814 HFONT hFont;
3815 PTEXTOBJ TextObj;
3816 PFONTGDI FontGdi;
3817 DWORD Result = GDI_ERROR;
3818
3819 Dc = DC_LockDc(hDC);
3820 if (Dc == NULL)
3821 {
3822 SetLastWin32Error(ERROR_INVALID_HANDLE);
3823 return GDI_ERROR;
3824 }
3825 hFont = Dc->w.hFont;
3826 TextObj = TEXTOBJ_LockText(hFont);
3827 DC_UnlockDc(Dc);
3828
3829 if (TextObj == NULL)
3830 {
3831 SetLastWin32Error(ERROR_INVALID_HANDLE);
3832 return GDI_ERROR;
3833 }
3834
3835 FontGdi = ObjToGDI(TextObj->Font, FONT);
3836
3837 IntLockFreeType;
3838
3839 if (FT_IS_SFNT(FontGdi->face))
3840 {
3841 if (Table)
3842 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
3843 (Table << 8 & 0xFF0000);
3844
3845 if (Buffer == NULL)
3846 Size = 0;
3847
3848 if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
3849 Result = Size;
3850 }
3851
3852 IntUnLockFreeType;
3853
3854 TEXTOBJ_UnlockText(TextObj);
3855
3856 return Result;
3857 }
3858
3859 static UINT FASTCALL
3860 GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
3861 {
3862 ANSI_STRING EntryFaceNameA;
3863 UNICODE_STRING EntryFaceNameW;
3864 unsigned Size;
3865 OUTLINETEXTMETRICW *Otm;
3866 LONG WeightDiff;
3867 NTSTATUS Status;
3868 UINT Score = 1;
3869
3870 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
3871 Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
3872 if (NT_SUCCESS(Status))
3873 {
3874 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
3875 {
3876 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
3877 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
3878 }
3879 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
3880 {
3881 Score += 49;
3882 }
3883 RtlFreeUnicodeString(&EntryFaceNameW);
3884 }
3885
3886 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3887 Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
3888 if (NULL == Otm)
3889 {
3890 return Score;
3891 }
3892 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
3893
3894 if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
3895 (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
3896 {
3897 Score += 25;
3898 }
3899 if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
3900 {
3901 WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
3902 }
3903 else
3904 {
3905 WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
3906 }
3907 Score += (1000 - WeightDiff) / (1000 / 25);
3908
3909 ExFreePool(Otm);
3910
3911 return Score;
3912 }
3913
3914 static __inline VOID
3915 FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
3916 PUNICODE_STRING FaceName, PLIST_ENTRY Head)
3917 {
3918 PLIST_ENTRY Entry;
3919 PFONT_ENTRY CurrentEntry;
3920 FONTGDI *FontGDI;
3921 UINT Score;
3922
3923 Entry = Head->Flink;
3924 while (Entry != Head)
3925 {
3926 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
3927
3928 FontGDI = CurrentEntry->Font;
3929 ASSERT(FontGDI);
3930
3931 Score = GetFontScore(LogFont, FaceName, FontGDI);
3932 if (*MatchScore == 0 || *MatchScore < Score)
3933 {
3934 *FontObj = GDIToObj(FontGDI, FONT);
3935 *MatchScore = Score;
3936 }
3937 Entry = Entry->Flink;
3938 }
3939 }
3940
3941 static __inline BOOLEAN
3942 SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
3943 LPCWSTR Key)
3944 {
3945 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
3946 NTSTATUS Status;
3947 UNICODE_STRING Value;
3948
3949 RtlInitUnicodeString(&Value, NULL);
3950
3951 QueryTable[0].QueryRoutine = NULL;
3952 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
3953 RTL_QUERY_REGISTRY_REQUIRED;
3954 QueryTable[0].Name = FaceName->Buffer;
3955 QueryTable[0].EntryContext = &Value;
3956 QueryTable[0].DefaultType = REG_NONE;
3957 QueryTable[0].DefaultData = NULL;
3958 QueryTable[0].DefaultLength = 0;
3959
3960 QueryTable[1].QueryRoutine = NULL;
3961 QueryTable[1].Name = NULL;
3962
3963 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
3964 Key,
3965 QueryTable,
3966 NULL,
3967 NULL);
3968 if (NT_SUCCESS(Status))
3969 {
3970 RtlFreeUnicodeString(FaceName);
3971 *FaceName = Value;
3972 }
3973
3974 return NT_SUCCESS(Status);
3975 }
3976
3977 static __inline void
3978 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
3979 {
3980 if (10 < Level) /* Enough is enough */
3981 {
3982 return;
3983 }
3984
3985 if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
3986 SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
3987 {
3988 SubstituteFontFamily(FaceName, Level + 1);
3989 }
3990 }
3991
3992 NTSTATUS FASTCALL
3993 TextIntRealizeFont(HFONT FontHandle)
3994 {
3995 NTSTATUS Status = STATUS_SUCCESS;
3996 PTEXTOBJ TextObj;
3997 UNICODE_STRING FaceName;
3998 PW32PROCESS Win32Process;
3999 UINT MatchScore;
4000
4001 TextObj = TEXTOBJ_LockText(FontHandle);
4002 if (NULL == TextObj)
4003 {
4004 return STATUS_INVALID_HANDLE;
4005 }
4006
4007 if (TextObj->Initialized)
4008 {
4009 TEXTOBJ_UnlockText(TextObj);
4010 return STATUS_SUCCESS;
4011 }
4012
4013 if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.lfFaceName))
4014 {
4015 TEXTOBJ_UnlockText(TextObj);
4016 return STATUS_NO_MEMORY;
4017 }
4018 SubstituteFontFamily(&FaceName, 0);
4019 MatchScore = 0;
4020 TextObj->Font = NULL;
4021
4022 /* First search private fonts */
4023 Win32Process = PsGetCurrentProcessWin32Process();
4024 IntLockProcessPrivateFonts(Win32Process);
4025 FindBestFontFromList(&TextObj->Font, &MatchScore,
4026 &TextObj->logfont, &FaceName,
4027 &Win32Process->PrivateFontListHead);
4028 IntUnLockProcessPrivateFonts(Win32Process);
4029
4030 /* Search system fonts */
4031 IntLockGlobalFonts;
4032 FindBestFontFromList(&TextObj->Font, &MatchScore,
4033 &TextObj->logfont, &FaceName,
4034 &FontListHead);
4035 IntUnLockGlobalFonts;
4036
4037 if (NULL == TextObj->Font)
4038 {
4039 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
4040 TextObj->logfont.lfFaceName);
4041 Status = STATUS_NOT_FOUND;
4042 }
4043 else
4044 {
4045 TextObj->Initialized = TRUE;
4046 Status = STATUS_SUCCESS;
4047 }
4048
4049 RtlFreeUnicodeString(&FaceName);
4050 TEXTOBJ_UnlockText(TextObj);
4051
4052 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
4053
4054 return Status;
4055 }
4056
4057 INT FASTCALL
4058 FontGetObject(PTEXTOBJ Font, INT Count, PVOID Buffer)
4059 {
4060 if (Buffer)
4061 {
4062 if (Count < sizeof(LOGFONTW))
4063 {
4064 SetLastWin32Error(ERROR_BUFFER_OVERFLOW);
4065 return 0;
4066 }
4067
4068 RtlCopyMemory(Buffer, &Font->logfont, sizeof(LOGFONTW));
4069 }
4070
4071 return sizeof(LOGFONTW);
4072 }
4073
4074
4075 /* Remove this HAX! after the below function is done in GDI32.DLL! */
4076 INT
4077 STDCALL
4078 NtGdiGetSetTextCharExtra( HDC hDC, INT CharExtra, BOOL Set)
4079 {
4080 /* Ulta-Ugly Hax! */
4081 INT Ret = 0x80000000;
4082 DPRINT("TextCharacterExtra %d", CharExtra);
4083 PDC dc = DC_LockDc ( hDC );
4084 if (!dc)
4085 {
4086 SetLastWin32Error(ERROR_INVALID_HANDLE);
4087 return Ret;
4088 }
4089 Ret = dc->w.charExtra;
4090 if( Set ) dc->w.charExtra = CharExtra;
4091 DC_UnlockDc(dc);
4092 return (Ret);
4093 }
4094
4095 /* EOF */