NtGdiGetObject
[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 /*
1482 Misses++;
1483 if (Misses>100) {
1484 DbgPrint ("Hits: %d Misses: %d\n", Hits, Misses);
1485 Hits = Misses = 0;
1486 }
1487 */
1488 return NULL;
1489 }
1490
1491 RemoveEntryList(CurrentEntry);
1492 InsertHeadList(&FontCacheListHead, CurrentEntry);
1493
1494 // DbgPrint("Hit! %x\n", FontEntry->Glyph);
1495 /*
1496 Hits++;
1497
1498 if (Hits>100) {
1499 DbgPrint ("Hits: %d Misses: %d\n", Hits, Misses);
1500 Hits = Misses = 0;
1501 }
1502 */
1503 return FontEntry->Glyph;
1504 }
1505
1506 FT_Glyph STDCALL
1507 NtGdiGlyphCacheSet(
1508 FT_Face Face,
1509 INT GlyphIndex,
1510 INT Height,
1511 FT_GlyphSlot GlyphSlot,
1512 FT_Render_Mode RenderMode)
1513 {
1514 FT_Glyph GlyphCopy;
1515 INT error;
1516 PFONT_CACHE_ENTRY NewEntry;
1517
1518 // DbgPrint("CacheSet.\n");
1519
1520 error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
1521 if (error)
1522 {
1523 DbgPrint("Failure caching glyph.\n");
1524 return NULL;
1525 };
1526 error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
1527 if (error)
1528 {
1529 DbgPrint("Failure rendering glyph.\n");
1530 return NULL;
1531 };
1532
1533 NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
1534 if (!NewEntry)
1535 {
1536 DbgPrint("Alloc failure caching glyph.\n");
1537 FT_Done_Glyph(GlyphCopy);
1538 return NULL;
1539 }
1540
1541 NewEntry->GlyphIndex = GlyphIndex;
1542 NewEntry->Face = Face;
1543 NewEntry->Glyph = GlyphCopy;
1544 NewEntry->Height = Height;
1545
1546 InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
1547 if (FontCacheNumEntries++ > MAX_FONT_CACHE) {
1548 NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
1549 FT_Done_Glyph(NewEntry->Glyph);
1550 RemoveTailList(&FontCacheListHead);
1551 ExFreePool(NewEntry);
1552 FontCacheNumEntries--;
1553 }
1554
1555 // DbgPrint("Returning the glyphcopy: %x\n", GlyphCopy);
1556
1557 return GlyphCopy;
1558 }
1559
1560 BOOL STDCALL
1561 NtGdiExtTextOut(
1562 HDC hDC,
1563 INT XStart,
1564 INT YStart,
1565 UINT fuOptions,
1566 CONST RECT *lprc,
1567 LPCWSTR UnsafeString,
1568 UINT Count,
1569 CONST INT *UnsafeDx)
1570 {
1571 /*
1572 * FIXME:
1573 * Call EngTextOut, which does the real work (calling DrvTextOut where
1574 * appropriate)
1575 */
1576
1577 DC *dc;
1578 SURFOBJ *SurfObj;
1579 BITMAPOBJ *BitmapObj = NULL;
1580 int error, glyph_index, n, i;
1581 FT_Face face;
1582 FT_GlyphSlot glyph;
1583 FT_Glyph realglyph;
1584 FT_BitmapGlyph realglyph2;
1585 LONGLONG TextLeft, RealXStart;
1586 ULONG TextTop, previous, BackgroundLeft;
1587 FT_Bool use_kerning;
1588 RECTL DestRect, MaskRect, SpecifiedDestRect;
1589 POINTL SourcePoint, BrushOrigin;
1590 HBRUSH hBrushFg = NULL;
1591 PGDIBRUSHOBJ BrushFg = NULL;
1592 GDIBRUSHINST BrushFgInst;
1593 HBRUSH hBrushBg = NULL;
1594 PGDIBRUSHOBJ BrushBg = NULL;
1595 GDIBRUSHINST BrushBgInst;
1596 HBITMAP HSourceGlyph;
1597 SURFOBJ *SourceGlyphSurf;
1598 SIZEL bitSize;
1599 FT_CharMap found = 0, charmap;
1600 INT yoff;
1601 FONTOBJ *FontObj;
1602 PFONTGDI FontGDI;
1603 PTEXTOBJ TextObj = NULL;
1604 PPALGDI PalDestGDI;
1605 XLATEOBJ *XlateObj=NULL, *XlateObj2=NULL;
1606 ULONG Mode;
1607 FT_Render_Mode RenderMode;
1608 BOOLEAN Render;
1609 NTSTATUS Status;
1610 INT *Dx = NULL;
1611 POINT Start;
1612 BOOL DoBreak = FALSE;
1613 LPCWSTR String, SafeString = NULL;
1614
1615 // TODO: Write test-cases to exactly match real Windows in different
1616 // bad parameters (e.g. does Windows check the DC or the RECT first?).
1617 dc = DC_LockDc(hDC);
1618 if (!dc)
1619 {
1620 SetLastWin32Error(ERROR_INVALID_HANDLE);
1621 return FALSE;
1622 }
1623 if (dc->IsIC)
1624 {
1625 DC_UnlockDc(dc);
1626 /* Yes, Windows really returns TRUE in this case */
1627 return TRUE;
1628 }
1629
1630 /* Check if String is valid */
1631 if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
1632 {
1633 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1634 goto fail;
1635 }
1636 if (Count > 0)
1637 {
1638 SafeString = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), TAG_GDITEXT);
1639 if (!SafeString)
1640 {
1641 goto fail;
1642 }
1643 Status = MmCopyFromCaller(SafeString, UnsafeString, Count * sizeof(WCHAR));
1644 if (! NT_SUCCESS(Status))
1645 {
1646 goto fail;
1647 }
1648 }
1649 String = SafeString;
1650
1651 if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
1652 {
1653 // At least one of the two flags were specified. Copy lprc. Once.
1654 Status = MmCopyFromCaller(&SpecifiedDestRect, lprc, sizeof(RECT));
1655 if (!NT_SUCCESS(Status))
1656 {
1657 DC_UnlockDc(dc);
1658 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1659 return FALSE;
1660 }
1661 IntLPtoDP(dc, (POINT *) &SpecifiedDestRect, 2);
1662 }
1663
1664 if (NULL != UnsafeDx && Count > 0)
1665 {
1666 Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
1667 if (NULL == Dx)
1668 {
1669 goto fail;
1670 }
1671 Status = MmCopyFromCaller(Dx, UnsafeDx, Count * sizeof(INT));
1672 if (! NT_SUCCESS(Status))
1673 {
1674 goto fail;
1675 }
1676 }
1677
1678 BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
1679 if ( !BitmapObj )
1680 {
1681 goto fail;
1682 }
1683 SurfObj = &BitmapObj->SurfObj;
1684 ASSERT(SurfObj);
1685
1686 Start.x = XStart; Start.y = YStart;
1687 IntLPtoDP(dc, &Start, 1);
1688
1689 RealXStart = (Start.x + dc->w.DCOrgX) << 6;
1690 YStart = Start.y + dc->w.DCOrgY;
1691
1692 /* Create the brushes */
1693 PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
1694 if ( !PalDestGDI )
1695 Mode = PAL_RGB;
1696 else
1697 {
1698 Mode = PalDestGDI->Mode;
1699 PALETTE_UnlockPalette(PalDestGDI);
1700 }
1701 XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
1702 if ( !XlateObj )
1703 {
1704 goto fail;
1705 }
1706 hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor), 0);
1707 if ( !hBrushFg )
1708 {
1709 goto fail;
1710 }
1711 BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
1712 if ( !BrushFg )
1713 {
1714 goto fail;
1715 }
1716 IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);
1717 if ((fuOptions & ETO_OPAQUE) || dc->w.backgroundMode == OPAQUE)
1718 {
1719 hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor), 0);
1720 if ( !hBrushBg )
1721 {
1722 goto fail;
1723 }
1724 BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
1725 if ( !BrushBg )
1726 {
1727 goto fail;
1728 }
1729 IntGdiInitBrushInstance(&BrushBgInst, BrushBg, NULL);
1730 }
1731 XlateObj2 = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, Mode, NULL, dc->w.hPalette);
1732 if ( !XlateObj2 )
1733 {
1734 goto fail;
1735 }
1736
1737 SourcePoint.x = 0;
1738 SourcePoint.y = 0;
1739 MaskRect.left = 0;
1740 MaskRect.top = 0;
1741 BrushOrigin.x = 0;
1742 BrushOrigin.y = 0;
1743
1744 if ((fuOptions & ETO_OPAQUE) && lprc)
1745 {
1746 DestRect.left = SpecifiedDestRect.left + dc->w.DCOrgX;
1747 DestRect.top = SpecifiedDestRect.top + dc->w.DCOrgY;
1748 DestRect.right = SpecifiedDestRect.right + dc->w.DCOrgX;
1749 DestRect.bottom = SpecifiedDestRect.bottom + dc->w.DCOrgY;
1750 IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
1751 IntEngBitBlt(
1752 &BitmapObj->SurfObj,
1753 NULL,
1754 NULL,
1755 dc->CombinedClip,
1756 NULL,
1757 &DestRect,
1758 &SourcePoint,
1759 &SourcePoint,
1760 &BrushBgInst.BrushObject,
1761 &BrushOrigin,
1762 ROP3_TO_ROP4(PATCOPY));
1763 fuOptions &= ~ETO_OPAQUE;
1764 }
1765 else
1766 {
1767 if (dc->w.backgroundMode == OPAQUE)
1768 {
1769 fuOptions |= ETO_OPAQUE;
1770 }
1771 }
1772
1773 TextObj = TEXTOBJ_LockText(dc->w.hFont);
1774 if(TextObj == NULL)
1775 {
1776 goto fail;
1777 }
1778
1779 FontObj = TextObj->Font;
1780 ASSERT(FontObj);
1781 FontGDI = ObjToGDI(FontObj, FONT);
1782 ASSERT(FontGDI);
1783
1784 IntLockFreeType;
1785 face = FontGDI->face;
1786 if (face->charmap == NULL)
1787 {
1788 DPRINT("WARNING: No charmap selected!\n");
1789 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
1790
1791 for (n = 0; n < face->num_charmaps; n++)
1792 {
1793 charmap = face->charmaps[n];
1794 DPRINT("found charmap encoding: %u\n", charmap->encoding);
1795 if (charmap->encoding != 0)
1796 {
1797 found = charmap;
1798 break;
1799 }
1800 }
1801 if (!found)
1802 {
1803 DPRINT1("WARNING: Could not find desired charmap!\n");
1804 }
1805 error = FT_Set_Charmap(face, found);
1806 if (error)
1807 {
1808 DPRINT1("WARNING: Could not set the charmap!\n");
1809 }
1810 }
1811
1812 Render = IntIsFontRenderingEnabled();
1813 if (Render)
1814 RenderMode = IntGetFontRenderMode(&TextObj->logfont);
1815 else
1816 RenderMode = FT_RENDER_MODE_MONO;
1817
1818 error = FT_Set_Pixel_Sizes(
1819 face,
1820 TextObj->logfont.lfWidth,
1821 /* FIXME should set character height if neg */
1822 (TextObj->logfont.lfHeight < 0 ?
1823 - TextObj->logfont.lfHeight :
1824 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
1825 if (error)
1826 {
1827 DPRINT1("Error in setting pixel sizes: %u\n", error);
1828 IntUnLockFreeType;
1829 goto fail;
1830 }
1831
1832 /*
1833 * Process the vertical alignment and determine the yoff.
1834 */
1835
1836 if (dc->w.textAlign & TA_BASELINE)
1837 yoff = 0;
1838 else if (dc->w.textAlign & TA_BOTTOM)
1839 yoff = -face->size->metrics.descender >> 6;
1840 else /* TA_TOP */
1841 yoff = face->size->metrics.ascender >> 6;
1842
1843 use_kerning = FT_HAS_KERNING(face);
1844 previous = 0;
1845
1846 /*
1847 * Process the horizontal alignment and modify XStart accordingly.
1848 */
1849
1850 if (dc->w.textAlign & (TA_RIGHT | TA_CENTER))
1851 {
1852 ULONGLONG TextWidth = 0;
1853 LPCWSTR TempText = String;
1854 int Start;
1855
1856 /*
1857 * Calculate width of the text.
1858 */
1859
1860 if (NULL != Dx)
1861 {
1862 Start = Count < 2 ? 0 : Count - 2;
1863 TextWidth = Count < 2 ? 0 : (Dx[Count - 2] << 6);
1864 }
1865 else
1866 {
1867 Start = 0;
1868 }
1869 TempText = String + Start;
1870
1871 for (i = Start; i < Count; i++)
1872 {
1873 glyph_index = FT_Get_Char_Index(face, *TempText);
1874 if (!(realglyph = NtGdiGlyphCacheGet(face, glyph_index, TextObj->logfont.lfHeight)))
1875 {
1876 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1877 if (error)
1878 {
1879 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1880 }
1881
1882 glyph = face->glyph;
1883 realglyph = NtGdiGlyphCacheSet(face, glyph_index, TextObj->logfont.lfHeight, glyph, RenderMode);
1884 }
1885 /* retrieve kerning distance */
1886 if (use_kerning && previous && glyph_index)
1887 {
1888 FT_Vector delta;
1889 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1890 TextWidth += delta.x;
1891 }
1892
1893 TextWidth += realglyph->advance.x >> 10;
1894
1895 previous = glyph_index;
1896 TempText++;
1897 }
1898
1899 previous = 0;
1900
1901 if (dc->w.textAlign & TA_RIGHT)
1902 {
1903 RealXStart -= TextWidth;
1904 }
1905 else
1906 {
1907 RealXStart -= TextWidth / 2;
1908 }
1909 }
1910
1911 TextLeft = RealXStart;
1912 TextTop = YStart;
1913 BackgroundLeft = (RealXStart + 32) >> 6;
1914
1915 /*
1916 * The main rendering loop.
1917 */
1918
1919 for (i = 0; i < Count; i++)
1920 {
1921 glyph_index = FT_Get_Char_Index(face, *String);
1922 if (!(realglyph = NtGdiGlyphCacheGet(face, glyph_index, TextObj->logfont.lfHeight)))
1923 {
1924 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
1925
1926 if (error)
1927 {
1928 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
1929 IntUnLockFreeType;
1930 goto fail;
1931 }
1932 glyph = face->glyph;
1933 realglyph = NtGdiGlyphCacheSet(face, glyph_index, TextObj->logfont.lfHeight, glyph, RenderMode);
1934 }
1935 // DbgPrint("realglyph: %x\n", realglyph);
1936 // DbgPrint("TextLeft: %d\n", TextLeft);
1937
1938 /* retrieve kerning distance and move pen position */
1939 if (use_kerning && previous && glyph_index && NULL == Dx)
1940 {
1941 FT_Vector delta;
1942 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
1943 TextLeft += delta.x;
1944 }
1945 // DPRINT1("TextLeft: %d\n", TextLeft);
1946 // DPRINT1("TextTop: %d\n", TextTop);
1947
1948 if (realglyph->format == ft_glyph_format_outline)
1949 {
1950 DbgPrint("Should already be done\n");
1951 // error = FT_Render_Glyph(glyph, RenderMode);
1952 error = FT_Glyph_To_Bitmap(&realglyph, RenderMode, 0, 0);
1953 if (error)
1954 {
1955 DPRINT1("WARNING: Failed to render glyph!\n");
1956 goto fail;
1957 }
1958 }
1959 realglyph2 = (FT_BitmapGlyph)realglyph;
1960
1961 // DPRINT1("Pitch: %d\n", pitch);
1962 // DPRINT1("Advance: %d\n", realglyph->advance.x);
1963
1964 if (fuOptions & ETO_OPAQUE)
1965 {
1966 DestRect.left = BackgroundLeft;
1967 DestRect.right = (TextLeft + (realglyph->advance.x >> 10) + 32) >> 6;
1968 DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6);
1969 DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6);
1970 IntEngBitBlt(
1971 &BitmapObj->SurfObj,
1972 NULL,
1973 NULL,
1974 dc->CombinedClip,
1975 NULL,
1976 &DestRect,
1977 &SourcePoint,
1978 &SourcePoint,
1979 &BrushBgInst.BrushObject,
1980 &BrushOrigin,
1981 ROP3_TO_ROP4(PATCOPY));
1982 BackgroundLeft = DestRect.right;
1983 }
1984
1985 DestRect.left = ((TextLeft + 32) >> 6) + realglyph2->left;
1986 DestRect.right = DestRect.left + realglyph2->bitmap.width;
1987 DestRect.top = TextTop + yoff - realglyph2->top;
1988 DestRect.bottom = DestRect.top + realglyph2->bitmap.rows;
1989
1990 // DbgPrint("lrtb %d %d %d %d\n", DestRect.left, DestRect.right,
1991 // DestRect.top, DestRect.bottom);
1992 // DbgPrint("specified lrtb %d %d %d %d\n", SpecifiedDestRect.left, SpecifiedDestRect.right,
1993 // SpecifiedDestRect.top, SpecifiedDestRect.bottom);
1994 // DbgPrint ("dc->w.DCOrgX: %d\n", dc->w.DCOrgX);
1995
1996 bitSize.cx = realglyph2->bitmap.width;
1997 bitSize.cy = realglyph2->bitmap.rows;
1998 MaskRect.right = realglyph2->bitmap.width;
1999 MaskRect.bottom = realglyph2->bitmap.rows;
2000
2001 /*
2002 * We should create the bitmap out of the loop at the biggest possible
2003 * glyph size. Then use memset with 0 to clear it and sourcerect to
2004 * limit the work of the transbitblt.
2005 *
2006 * FIXME: DIB bitmaps should have an lDelta which is a multiple of 4.
2007 * Here we pass in the pitch from the FreeType bitmap, which is not
2008 * guaranteed to be a multiple of 4. If it's not, we should expand
2009 * the FreeType bitmap to a temporary bitmap.
2010 */
2011
2012 HSourceGlyph = EngCreateBitmap(bitSize, realglyph2->bitmap.pitch,
2013 (realglyph2->bitmap.pixel_mode == ft_pixel_mode_grays) ?
2014 BMF_8BPP : BMF_1BPP, BMF_TOPDOWN,
2015 realglyph2->bitmap.buffer);
2016 if ( !HSourceGlyph )
2017 {
2018 DPRINT1("WARNING: EngLockSurface() failed!\n");
2019 FT_Done_Glyph(realglyph);
2020 IntUnLockFreeType;
2021 goto fail;
2022 }
2023 SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
2024 if ( !SourceGlyphSurf )
2025 {
2026 EngDeleteSurface((HSURF)HSourceGlyph);
2027 DPRINT1("WARNING: EngLockSurface() failed!\n");
2028 IntUnLockFreeType;
2029 goto fail;
2030 }
2031
2032 /*
2033 * Use the font data as a mask to paint onto the DCs surface using a
2034 * brush.
2035 */
2036
2037 if (lprc &&
2038 (fuOptions & ETO_CLIPPED) &&
2039 DestRect.right >= SpecifiedDestRect.right + dc->w.DCOrgX)
2040 {
2041 // We do the check '>=' instead of '>' to possibly save an iteration
2042 // through this loop, since it's breaking after the drawing is done,
2043 // and x is always incremented.
2044 DestRect.right = SpecifiedDestRect.right + dc->w.DCOrgX;
2045 DoBreak = TRUE;
2046 }
2047
2048 IntEngMaskBlt(
2049 SurfObj,
2050 SourceGlyphSurf,
2051 dc->CombinedClip,
2052 XlateObj,
2053 XlateObj2,
2054 &DestRect,
2055 &SourcePoint,
2056 (PPOINTL)&MaskRect,
2057 &BrushFgInst.BrushObject,
2058 &BrushOrigin);
2059
2060 EngUnlockSurface(SourceGlyphSurf);
2061 EngDeleteSurface((HSURF)HSourceGlyph);
2062
2063 if (DoBreak)
2064 {
2065 break;
2066 }
2067
2068 if (NULL == Dx)
2069 {
2070 TextLeft += realglyph->advance.x >> 10;
2071 // DbgPrint("new TextLeft: %d\n", TextLeft);
2072 }
2073 else
2074 {
2075 TextLeft += Dx[i] << 6;
2076 // DbgPrint("new TextLeft2: %d\n", TextLeft);
2077 }
2078 previous = glyph_index;
2079
2080 String++;
2081 }
2082
2083 IntUnLockFreeType;
2084
2085 EngDeleteXlate(XlateObj);
2086 EngDeleteXlate(XlateObj2);
2087 BITMAPOBJ_UnlockBitmap(BitmapObj);
2088 if(TextObj != NULL)
2089 TEXTOBJ_UnlockText(TextObj);
2090 if (hBrushBg != NULL)
2091 {
2092 BRUSHOBJ_UnlockBrush(BrushBg);
2093 NtGdiDeleteObject(hBrushBg);
2094 }
2095 BRUSHOBJ_UnlockBrush(BrushFg);
2096 NtGdiDeleteObject(hBrushFg);
2097 if (NULL != SafeString)
2098 {
2099 ExFreePool((void*)SafeString);
2100 }
2101 if (NULL != Dx)
2102 {
2103 ExFreePool(Dx);
2104 }
2105 DC_UnlockDc( dc );
2106
2107 return TRUE;
2108
2109 fail:
2110 if ( XlateObj2 != NULL )
2111 EngDeleteXlate(XlateObj2);
2112 if ( XlateObj != NULL )
2113 EngDeleteXlate(XlateObj);
2114 if(TextObj != NULL)
2115 TEXTOBJ_UnlockText(TextObj);
2116 BITMAPOBJ_UnlockBitmap(BitmapObj);
2117 if (hBrushBg != NULL)
2118 {
2119 BRUSHOBJ_UnlockBrush(BrushBg);
2120 NtGdiDeleteObject(hBrushBg);
2121 }
2122 if (hBrushFg != NULL)
2123 {
2124 BRUSHOBJ_UnlockBrush(BrushFg);
2125 NtGdiDeleteObject(hBrushFg);
2126 }
2127 if (NULL != SafeString)
2128 {
2129 ExFreePool((void*)SafeString);
2130 }
2131 if (NULL != Dx)
2132 {
2133 ExFreePool(Dx);
2134 }
2135 DC_UnlockDc(dc);
2136
2137 return FALSE;
2138 }
2139
2140 BOOL
2141 STDCALL
2142 NtGdiGetAspectRatioFilterEx(HDC hDC,
2143 LPSIZE AspectRatio)
2144 {
2145 UNIMPLEMENTED;
2146 return FALSE;
2147 }
2148
2149 BOOL
2150 STDCALL
2151 NtGdiGetCharABCWidths(HDC hDC,
2152 UINT FirstChar,
2153 UINT LastChar,
2154 LPABC abc)
2155 {
2156 LPABC SafeBuffer;
2157 PDC dc;
2158 PTEXTOBJ TextObj;
2159 PFONTGDI FontGDI;
2160 FT_Face face;
2161 FT_CharMap charmap, found = NULL;
2162 UINT i, glyph_index, BufferSize;
2163 HFONT hFont = 0;
2164 NTSTATUS Status;
2165
2166 if (LastChar < FirstChar)
2167 {
2168 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2169 return FALSE;
2170 }
2171
2172 BufferSize = (LastChar - FirstChar + 1) * sizeof(ABC);
2173 SafeBuffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
2174 if (SafeBuffer == NULL)
2175 {
2176 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2177 return FALSE;
2178 }
2179
2180 dc = DC_LockDc(hDC);
2181 if (dc == NULL)
2182 {
2183 ExFreePool(SafeBuffer);
2184 SetLastWin32Error(ERROR_INVALID_HANDLE);
2185 return FALSE;
2186 }
2187 hFont = dc->w.hFont;
2188 TextObj = TEXTOBJ_LockText(hFont);
2189 DC_UnlockDc(dc);
2190
2191 if (TextObj == NULL)
2192 {
2193 ExFreePool(SafeBuffer);
2194 SetLastWin32Error(ERROR_INVALID_HANDLE);
2195 return FALSE;
2196 }
2197
2198 FontGDI = ObjToGDI(TextObj->Font, FONT);
2199
2200 face = FontGDI->face;
2201 if (face->charmap == NULL)
2202 {
2203 for (i = 0; i < face->num_charmaps; i++)
2204 {
2205 charmap = face->charmaps[i];
2206 if (charmap->encoding != 0)
2207 {
2208 found = charmap;
2209 break;
2210 }
2211 }
2212
2213 if (!found)
2214 {
2215 DPRINT1("WARNING: Could not find desired charmap!\n");
2216 ExFreePool(SafeBuffer);
2217 SetLastWin32Error(ERROR_INVALID_HANDLE);
2218 return FALSE;
2219 }
2220
2221 IntLockFreeType;
2222 FT_Set_Charmap(face, found);
2223 IntUnLockFreeType;
2224 }
2225
2226 IntLockFreeType;
2227 FT_Set_Pixel_Sizes(face,
2228 TextObj->logfont.lfWidth,
2229 /* FIXME should set character height if neg */
2230 (TextObj->logfont.lfHeight < 0 ? - TextObj->logfont.lfHeight :
2231 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
2232
2233 for (i = FirstChar; i <= LastChar; i++)
2234 {
2235 int adv, lsb, bbx, left, right;
2236
2237 glyph_index = FT_Get_Char_Index(face, i);
2238 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2239
2240 left = (INT)face->glyph->metrics.horiBearingX & -64;
2241 right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
2242 adv = (face->glyph->advance.x + 32) >> 6;
2243
2244 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
2245 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same!*/
2246
2247 lsb = left >> 6;
2248 bbx = (right - left) >> 6;
2249 /*
2250 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
2251 */
2252 SafeBuffer[i - FirstChar].abcA = lsb;
2253 SafeBuffer[i - FirstChar].abcB = bbx;
2254 SafeBuffer[i - FirstChar].abcC = adv - lsb - bbx;
2255 }
2256 IntUnLockFreeType;
2257 TEXTOBJ_UnlockText(TextObj);
2258 Status = MmCopyToCaller(abc, SafeBuffer, BufferSize);
2259 if (! NT_SUCCESS(Status))
2260 {
2261 SetLastNtError(Status);
2262 ExFreePool(SafeBuffer);
2263 return FALSE;
2264 }
2265 ExFreePool(SafeBuffer);
2266 DPRINT("NtGdiGetCharABCWidths Worked!\n");
2267 return TRUE;
2268 }
2269
2270 BOOL
2271 STDCALL
2272 NtGdiGetCharABCWidthsFloat(HDC hDC,
2273 UINT FirstChar,
2274 UINT LastChar,
2275 LPABCFLOAT abcF)
2276 {
2277 UNIMPLEMENTED;
2278 return FALSE;
2279 }
2280
2281 DWORD
2282 STDCALL
2283 NtGdiGetCharacterPlacement(HDC hDC,
2284 LPCWSTR String,
2285 int Count,
2286 int MaxExtent,
2287 LPGCP_RESULTSW Results,
2288 DWORD Flags)
2289 {
2290 UNIMPLEMENTED;
2291 return 0;
2292 }
2293
2294 BOOL
2295 STDCALL
2296 NtGdiGetCharWidth32(HDC hDC,
2297 UINT FirstChar,
2298 UINT LastChar,
2299 LPINT Buffer)
2300 {
2301 LPINT SafeBuffer;
2302 PDC dc;
2303 PTEXTOBJ TextObj;
2304 PFONTGDI FontGDI;
2305 FT_Face face;
2306 FT_CharMap charmap, found = NULL;
2307 UINT i, glyph_index, BufferSize;
2308 HFONT hFont = 0;
2309
2310 if (LastChar < FirstChar)
2311 {
2312 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2313 return FALSE;
2314 }
2315
2316 BufferSize = (LastChar - FirstChar + 1) * sizeof(INT);
2317 SafeBuffer = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
2318 if (SafeBuffer == NULL)
2319 {
2320 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2321 return FALSE;
2322 }
2323
2324 dc = DC_LockDc(hDC);
2325 if (dc == NULL)
2326 {
2327 ExFreePool(SafeBuffer);
2328 SetLastWin32Error(ERROR_INVALID_HANDLE);
2329 return FALSE;
2330 }
2331 hFont = dc->w.hFont;
2332 TextObj = TEXTOBJ_LockText(hFont);
2333 DC_UnlockDc(dc);
2334
2335 if (TextObj == NULL)
2336 {
2337 ExFreePool(SafeBuffer);
2338 SetLastWin32Error(ERROR_INVALID_HANDLE);
2339 return FALSE;
2340 }
2341
2342 FontGDI = ObjToGDI(TextObj->Font, FONT);
2343
2344 face = FontGDI->face;
2345 if (face->charmap == NULL)
2346 {
2347 for (i = 0; i < face->num_charmaps; i++)
2348 {
2349 charmap = face->charmaps[i];
2350 if (charmap->encoding != 0)
2351 {
2352 found = charmap;
2353 break;
2354 }
2355 }
2356
2357 if (!found)
2358 {
2359 DPRINT1("WARNING: Could not find desired charmap!\n");
2360 ExFreePool(SafeBuffer);
2361 SetLastWin32Error(ERROR_INVALID_HANDLE);
2362 return FALSE;
2363 }
2364
2365 IntLockFreeType;
2366 FT_Set_Charmap(face, found);
2367 IntUnLockFreeType;
2368 }
2369
2370 IntLockFreeType;
2371 FT_Set_Pixel_Sizes(face,
2372 TextObj->logfont.lfWidth,
2373 /* FIXME should set character height if neg */
2374 (TextObj->logfont.lfHeight < 0 ?
2375 - TextObj->logfont.lfHeight :
2376 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
2377
2378 for (i = FirstChar; i <= LastChar; i++)
2379 {
2380 glyph_index = FT_Get_Char_Index(face, i);
2381 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
2382 SafeBuffer[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
2383 }
2384 IntUnLockFreeType;
2385 TEXTOBJ_UnlockText(TextObj);
2386 MmCopyToCaller(Buffer, SafeBuffer, BufferSize);
2387 ExFreePool(SafeBuffer);
2388 return TRUE;
2389 }
2390
2391 BOOL
2392 STDCALL
2393 NtGdiGetCharWidthFloat(HDC hDC,
2394 UINT FirstChar,
2395 UINT LastChar,
2396 PFLOAT Buffer)
2397 {
2398 UNIMPLEMENTED;
2399 return FALSE;
2400 }
2401
2402 DWORD
2403 STDCALL
2404 NtGdiGetFontLanguageInfo(HDC hDC)
2405 {
2406 UNIMPLEMENTED;
2407 return 0;
2408 }
2409
2410 static
2411 void
2412 FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
2413 {
2414 pt->x.value = vec->x >> 6;
2415 pt->x.fract = (vec->x & 0x3f) << 10;
2416 pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
2417 pt->y.value = vec->y >> 6;
2418 pt->y.fract = (vec->y & 0x3f) << 10;
2419 pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
2420 return;
2421 }
2422
2423 /*
2424 This function builds an FT_Fixed from a float. It puts the integer part
2425 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
2426 It fails if the integer part of the float number is greater than SHORT_MAX.
2427 */
2428 static inline FT_Fixed FT_FixedFromFloat(float f)
2429 {
2430 short value = f;
2431 unsigned short fract = (f - value) * 0xFFFF;
2432 return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
2433 }
2434
2435 /*
2436 This function builds an FT_Fixed from a FIXED. It simply put f.value
2437 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
2438 */
2439 static inline FT_Fixed FT_FixedFromFIXED(FIXED f)
2440 {
2441 return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
2442 }
2443
2444 /*
2445 * Based on WineEngGetGlyphOutline
2446 *
2447 */
2448 ULONG
2449 APIENTRY
2450 NtGdiGetGlyphOutline(
2451 IN HDC hdc,
2452 IN WCHAR wch,
2453 IN UINT iFormat,
2454 OUT LPGLYPHMETRICS pgm,
2455 IN ULONG cjBuf,
2456 OUT OPTIONAL PVOID UnsafeBuf,
2457 IN LPMAT2 pmat2,
2458 IN BOOL bIgnoreRotation)
2459 {
2460 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
2461 PDC dc;
2462 PTEXTOBJ TextObj;
2463 PFONTGDI FontGDI;
2464 HFONT hFont = 0;
2465 NTSTATUS Status;
2466 GLYPHMETRICS gm;
2467 ULONG Size;
2468 FT_Face ft_face;
2469 FT_UInt glyph_index;
2470 DWORD width, height, pitch, needed = 0;
2471 FT_Bitmap ft_bitmap;
2472 FT_Error error;
2473 INT left, right, top = 0, bottom = 0;
2474 FT_Angle angle = 0;
2475 FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
2476 FLOAT eM11, widthRatio = 1.0;
2477 FT_Matrix transMat = identityMat;
2478 BOOL needsTransform = FALSE;
2479 INT orientation;
2480 LONG aveWidth;
2481 INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
2482 OUTLINETEXTMETRICW *potm;
2483 PVOID pvBuf = NULL;
2484
2485 DPRINT("%p, %d, %08x, %p, %08lx, %p, %p\n", hdc, wch, iFormat, pgm,
2486 cjBuf, UnsafeBuf, pmat2);
2487
2488 dc = DC_LockDc(hdc);
2489 if (!dc)
2490 {
2491 SetLastWin32Error(ERROR_INVALID_HANDLE);
2492 return GDI_ERROR;
2493 }
2494 eM11 = dc->w.xformWorld2Vport.eM11;
2495 hFont = dc->w.hFont;
2496 TextObj = TEXTOBJ_LockText(hFont);
2497 DC_UnlockDc(dc);
2498 if (!TextObj)
2499 {
2500 SetLastWin32Error(ERROR_INVALID_HANDLE);
2501 return GDI_ERROR;
2502 }
2503 FontGDI = ObjToGDI(TextObj->Font, FONT);
2504 ft_face = FontGDI->face;
2505
2506 aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.lfWidth: 0;
2507 orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.lfOrientation: 0;
2508
2509 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
2510 potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
2511 if (!potm)
2512 {
2513 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2514 TEXTOBJ_UnlockText(TextObj);
2515 return GDI_ERROR;
2516 }
2517 IntGetOutlineTextMetrics(FontGDI, Size, potm);
2518
2519 IntLockFreeType;
2520
2521 /* During testing, I never saw this used. In here just incase.*/
2522 if (ft_face->charmap == NULL)
2523 {
2524 DPRINT("WARNING: No charmap selected!\n");
2525 DPRINT("This font face has %d charmaps\n", ft_face->num_charmaps);
2526 int n;
2527 FT_CharMap found = 0, charmap;
2528
2529 for (n = 0; n < ft_face->num_charmaps; n++)
2530 {
2531 charmap = ft_face->charmaps[n];
2532 DPRINT("found charmap encoding: %u\n", charmap->encoding);
2533 if (charmap->encoding != 0)
2534 {
2535 found = charmap;
2536 break;
2537 }
2538 }
2539 if (!found)
2540 {
2541 DPRINT1("WARNING: Could not find desired charmap!\n");
2542 }
2543 error = FT_Set_Charmap(ft_face, found);
2544 if (error)
2545 {
2546 DPRINT1("WARNING: Could not set the charmap!\n");
2547 }
2548 }
2549
2550 // FT_Set_Pixel_Sizes(ft_face,
2551 // TextObj->logfont.lfWidth,
2552 /* FIXME should set character height if neg */
2553 // (TextObj->logfont.lfHeight < 0 ? - TextObj->logfont.lfHeight :
2554 // TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
2555
2556 TEXTOBJ_UnlockText(TextObj);
2557
2558 if (iFormat & GGO_GLYPH_INDEX)
2559 {
2560 glyph_index = wch;
2561 iFormat &= ~GGO_GLYPH_INDEX;
2562 }
2563 else glyph_index = FT_Get_Char_Index(ft_face, wch);
2564
2565 if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
2566 load_flags |= FT_LOAD_NO_BITMAP;
2567
2568 error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
2569 if (error)
2570 {
2571 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
2572 IntUnLockFreeType;
2573 if (potm) ExFreePool(potm);
2574 return GDI_ERROR;
2575 }
2576 IntUnLockFreeType;
2577
2578 if (aveWidth && potm)
2579 {
2580 widthRatio = (FLOAT)aveWidth * eM11 /
2581 (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
2582 }
2583
2584 left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
2585 right = (INT)((ft_face->glyph->metrics.horiBearingX +
2586 ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
2587
2588 adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
2589 lsb = left >> 6;
2590 bbx = (right - left) >> 6;
2591
2592 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
2593
2594 IntLockFreeType;
2595
2596 /* Scaling transform */
2597 if (aveWidth)
2598 {
2599 FT_Matrix scaleMat;
2600 DPRINT("Scaling Trans!\n");
2601 scaleMat.xx = FT_FixedFromFloat(widthRatio);
2602 scaleMat.xy = 0;
2603 scaleMat.yx = 0;
2604 scaleMat.yy = (1 << 16);
2605 FT_Matrix_Multiply(&scaleMat, &transMat);
2606 needsTransform = TRUE;
2607 }
2608
2609 /* Slant transform */
2610 if (potm->otmTextMetrics.tmItalic)
2611 {
2612 FT_Matrix slantMat;
2613 DPRINT("Slant Trans!\n");
2614 slantMat.xx = (1 << 16);
2615 slantMat.xy = ((1 << 16) >> 2);
2616 slantMat.yx = 0;
2617 slantMat.yy = (1 << 16);
2618 FT_Matrix_Multiply(&slantMat, &transMat);
2619 needsTransform = TRUE;
2620 }
2621
2622 /* Rotation transform */
2623 if (orientation)
2624 {
2625 FT_Matrix rotationMat;
2626 FT_Vector vecAngle;
2627 DPRINT("Rotation Trans!\n");
2628 angle = FT_FixedFromFloat((float)orientation / 10.0);
2629 FT_Vector_Unit(&vecAngle, angle);
2630 rotationMat.xx = vecAngle.x;
2631 rotationMat.xy = -vecAngle.y;
2632 rotationMat.yx = -rotationMat.xy;
2633 rotationMat.yy = rotationMat.xx;
2634 FT_Matrix_Multiply(&rotationMat, &transMat);
2635 needsTransform = TRUE;
2636 }
2637
2638 /* Extra transformation specified by caller */
2639 if (pmat2)
2640 {
2641 FT_Matrix extraMat;
2642 DPRINT("MAT2 Matrix Trans!\n");
2643 extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
2644 extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
2645 extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
2646 extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
2647 FT_Matrix_Multiply(&extraMat, &transMat);
2648 needsTransform = TRUE;
2649 }
2650
2651 if (potm) ExFreePool(potm); /* It looks like we are finished with potm ATM.*/
2652
2653 if (!needsTransform)
2654 {
2655 DPRINT("No Need to be Transformed!\n");
2656 top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
2657 bottom = (ft_face->glyph->metrics.horiBearingY -
2658 ft_face->glyph->metrics.height) & -64;
2659 gm.gmCellIncX = adv;
2660 gm.gmCellIncY = 0;
2661 }
2662 else
2663 {
2664 INT xc, yc;
2665 FT_Vector vec;
2666 for(xc = 0; xc < 2; xc++)
2667 {
2668 for(yc = 0; yc < 2; yc++)
2669 {
2670 vec.x = (ft_face->glyph->metrics.horiBearingX +
2671 xc * ft_face->glyph->metrics.width);
2672 vec.y = ft_face->glyph->metrics.horiBearingY -
2673 yc * ft_face->glyph->metrics.height;
2674 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
2675 FT_Vector_Transform(&vec, &transMat);
2676 if(xc == 0 && yc == 0)
2677 {
2678 left = right = vec.x;
2679 top = bottom = vec.y;
2680 }
2681 else
2682 {
2683 if(vec.x < left) left = vec.x;
2684 else if(vec.x > right) right = vec.x;
2685 if(vec.y < bottom) bottom = vec.y;
2686 else if(vec.y > top) top = vec.y;
2687 }
2688 }
2689 }
2690 left = left & -64;
2691 right = (right + 63) & -64;
2692 bottom = bottom & -64;
2693 top = (top + 63) & -64;
2694
2695 DPRINT("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
2696 vec.x = ft_face->glyph->metrics.horiAdvance;
2697 vec.y = 0;
2698 FT_Vector_Transform(&vec, &transMat);
2699 gm.gmCellIncX = (vec.x+63) >> 6;
2700 gm.gmCellIncY = -((vec.y+63) >> 6);
2701 }
2702 gm.gmBlackBoxX = (right - left) >> 6;
2703 gm.gmBlackBoxY = (top - bottom) >> 6;
2704 gm.gmptGlyphOrigin.x = left >> 6;
2705 gm.gmptGlyphOrigin.y = top >> 6;
2706
2707 DPRINT("CX %d CY %d BBX %d BBY %d GOX %d GOY %d\n",
2708 gm.gmCellIncX, gm.gmCellIncY,
2709 gm.gmBlackBoxX, gm.gmBlackBoxY,
2710 gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
2711
2712 IntUnLockFreeType;
2713
2714 if (pgm)
2715 {
2716 Status = MmCopyToCaller(pgm, &gm, sizeof(GLYPHMETRICS));
2717 if (! NT_SUCCESS(Status))
2718 {
2719 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2720 return GDI_ERROR;
2721 }
2722 DPRINT("Copied GLYPHMETRICS to User!\n");
2723 }
2724
2725 if (iFormat == GGO_METRICS)
2726 {
2727 DPRINT("GGO_METRICS Exit!\n");
2728 return 1; /* FIXME */
2729 }
2730
2731 if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
2732 {
2733 DPRINT1("loaded a bitmap\n");
2734 return GDI_ERROR;
2735 }
2736
2737 if (UnsafeBuf && cjBuf)
2738 {
2739 pvBuf = ExAllocatePoolWithTag(PagedPool, cjBuf, TAG_GDITEXT);
2740 if (pvBuf == NULL)
2741 {
2742 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2743 return GDI_ERROR;
2744 }
2745 RtlZeroMemory(pvBuf, cjBuf);
2746 }
2747
2748
2749 switch(iFormat)
2750 {
2751 case GGO_BITMAP:
2752 width = gm.gmBlackBoxX;
2753 height = gm.gmBlackBoxY;
2754 pitch = ((width + 31) >> 5) << 2;
2755 needed = pitch * height;
2756
2757 if(!pvBuf || !cjBuf) break;
2758
2759 switch(ft_face->glyph->format)
2760 {
2761 case ft_glyph_format_bitmap:
2762 {
2763 BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
2764 INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
2765 INT h = ft_face->glyph->bitmap.rows;
2766 while(h--)
2767 {
2768 RtlCopyMemory(dst, src, w);
2769 src += ft_face->glyph->bitmap.pitch;
2770 dst += pitch;
2771 }
2772 break;
2773 }
2774
2775 case ft_glyph_format_outline:
2776 ft_bitmap.width = width;
2777 ft_bitmap.rows = height;
2778 ft_bitmap.pitch = pitch;
2779 ft_bitmap.pixel_mode = ft_pixel_mode_mono;
2780 ft_bitmap.buffer = pvBuf;
2781
2782 IntLockFreeType;
2783 if(needsTransform)
2784 {
2785 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2786 }
2787 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2788 /* Note: FreeType will only set 'black' bits for us. */
2789 RtlZeroMemory(pvBuf, needed);
2790 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2791 IntUnLockFreeType;
2792 break;
2793
2794 default:
2795 DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
2796 if(pvBuf) ExFreePool(pvBuf);
2797 return GDI_ERROR;
2798 }
2799 break;
2800
2801 case GGO_GRAY2_BITMAP:
2802 case GGO_GRAY4_BITMAP:
2803 case GGO_GRAY8_BITMAP:
2804 {
2805 unsigned int mult, row, col;
2806 BYTE *start, *ptr;
2807
2808 width = gm.gmBlackBoxX;
2809 height = gm.gmBlackBoxY;
2810 pitch = (width + 3) / 4 * 4;
2811 needed = pitch * height;
2812
2813 if(!pvBuf || !cjBuf) break;
2814
2815 ft_bitmap.width = width;
2816 ft_bitmap.rows = height;
2817 ft_bitmap.pitch = pitch;
2818 ft_bitmap.pixel_mode = ft_pixel_mode_grays;
2819 ft_bitmap.buffer = pvBuf;
2820
2821 IntLockFreeType;
2822 if(needsTransform)
2823 {
2824 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
2825 }
2826 FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
2827 RtlZeroMemory(ft_bitmap.buffer, cjBuf);
2828 FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
2829 IntUnLockFreeType;
2830
2831 if(iFormat == GGO_GRAY2_BITMAP)
2832 mult = 4;
2833 else if(iFormat == GGO_GRAY4_BITMAP)
2834 mult = 16;
2835 else if(iFormat == GGO_GRAY8_BITMAP)
2836 mult = 64;
2837 else
2838 {
2839 ASSERT(0);
2840 break;
2841 }
2842
2843 start = pvBuf;
2844 for(row = 0; row < height; row++)
2845 {
2846 ptr = start;
2847 for(col = 0; col < width; col++, ptr++)
2848 {
2849 *ptr = (((int)*ptr) * mult + 128) / 256;
2850 }
2851 start += pitch;
2852 }
2853 break;
2854 }
2855
2856 case GGO_NATIVE:
2857 {
2858 int contour, point = 0, first_pt;
2859 FT_Outline *outline = &ft_face->glyph->outline;
2860 TTPOLYGONHEADER *pph;
2861 TTPOLYCURVE *ppc;
2862 DWORD pph_start, cpfx, type;
2863
2864 if(cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
2865
2866 IntLockFreeType;
2867 if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
2868
2869 for(contour = 0; contour < outline->n_contours; contour++)
2870 {
2871 pph_start = needed;
2872 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
2873 first_pt = point;
2874 if(pvBuf)
2875 {
2876 pph->dwType = TT_POLYGON_TYPE;
2877 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2878 }
2879 needed += sizeof(*pph);
2880 point++;
2881 while(point <= outline->contours[contour])
2882 {
2883 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
2884 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2885 TT_PRIM_LINE : TT_PRIM_QSPLINE;
2886 cpfx = 0;
2887 do
2888 {
2889 if(pvBuf)
2890 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2891 cpfx++;
2892 point++;
2893 } while(point <= outline->contours[contour] &&
2894 (outline->tags[point] & FT_Curve_Tag_On) ==
2895 (outline->tags[point-1] & FT_Curve_Tag_On));
2896
2897 /* At the end of a contour Windows adds the start point, but
2898 only for Beziers */
2899 if(point > outline->contours[contour] &&
2900 !(outline->tags[point-1] & FT_Curve_Tag_On))
2901 {
2902 if(pvBuf)
2903 FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
2904 cpfx++;
2905 }
2906 else if(point <= outline->contours[contour] &&
2907 outline->tags[point] & FT_Curve_Tag_On)
2908 {
2909 /* add closing pt for bezier */
2910 if(pvBuf)
2911 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2912 cpfx++;
2913 point++;
2914 }
2915 if(pvBuf)
2916 {
2917 ppc->wType = type;
2918 ppc->cpfx = cpfx;
2919 }
2920 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
2921 }
2922 if(pvBuf) pph->cb = needed - pph_start;
2923 }
2924 IntUnLockFreeType;
2925 break;
2926 }
2927 case GGO_BEZIER:
2928 {
2929 /* Convert the quadratic Beziers to cubic Beziers.
2930 The parametric eqn for a cubic Bezier is, from PLRM:
2931 r(t) = at^3 + bt^2 + ct + r0
2932 with the control points:
2933 r1 = r0 + c/3
2934 r2 = r1 + (c + b)/3
2935 r3 = r0 + c + b + a
2936
2937 A quadratic Beizer has the form:
2938 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2939
2940 So equating powers of t leads to:
2941 r1 = 2/3 p1 + 1/3 p0
2942 r2 = 2/3 p1 + 1/3 p2
2943 and of course r0 = p0, r3 = p2
2944 */
2945
2946 int contour, point = 0, first_pt;
2947 FT_Outline *outline = &ft_face->glyph->outline;
2948 TTPOLYGONHEADER *pph;
2949 TTPOLYCURVE *ppc;
2950 DWORD pph_start, cpfx, type;
2951 FT_Vector cubic_control[4];
2952 if(cjBuf == 0) pvBuf = NULL;
2953
2954 if (needsTransform && pvBuf)
2955 {
2956 IntLockFreeType;
2957 FT_Outline_Transform(outline, &transMat);
2958 IntUnLockFreeType;
2959 }
2960
2961 for(contour = 0; contour < outline->n_contours; contour++)
2962 {
2963 pph_start = needed;
2964 pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
2965 first_pt = point;
2966 if(pvBuf)
2967 {
2968 pph->dwType = TT_POLYGON_TYPE;
2969 FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
2970 }
2971 needed += sizeof(*pph);
2972 point++;
2973 while(point <= outline->contours[contour])
2974 {
2975 ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
2976 type = (outline->tags[point] & FT_Curve_Tag_On) ?
2977 TT_PRIM_LINE : TT_PRIM_CSPLINE;
2978 cpfx = 0;
2979 do
2980 {
2981 if(type == TT_PRIM_LINE)
2982 {
2983 if(pvBuf)
2984 FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
2985 cpfx++;
2986 point++;
2987 }
2988 else
2989 {
2990 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2991 so cpfx = 3n */
2992
2993 /* FIXME: Possible optimization in endpoint calculation
2994 if there are two consecutive curves */
2995 cubic_control[0] = outline->points[point-1];
2996 if(!(outline->tags[point-1] & FT_Curve_Tag_On))
2997 {
2998 cubic_control[0].x += outline->points[point].x + 1;
2999 cubic_control[0].y += outline->points[point].y + 1;
3000 cubic_control[0].x >>= 1;
3001 cubic_control[0].y >>= 1;
3002 }
3003 if(point+1 > outline->contours[contour])
3004 cubic_control[3] = outline->points[first_pt];
3005 else
3006 {
3007 cubic_control[3] = outline->points[point+1];
3008 if(!(outline->tags[point+1] & FT_Curve_Tag_On))
3009 {
3010 cubic_control[3].x += outline->points[point].x + 1;
3011 cubic_control[3].y += outline->points[point].y + 1;
3012 cubic_control[3].x >>= 1;
3013 cubic_control[3].y >>= 1;
3014 }
3015 }
3016 /* r1 = 1/3 p0 + 2/3 p1
3017 r2 = 1/3 p2 + 2/3 p1 */
3018 cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
3019 cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
3020 cubic_control[2] = cubic_control[1];
3021 cubic_control[1].x += (cubic_control[0].x + 1) / 3;
3022 cubic_control[1].y += (cubic_control[0].y + 1) / 3;
3023 cubic_control[2].x += (cubic_control[3].x + 1) / 3;
3024 cubic_control[2].y += (cubic_control[3].y + 1) / 3;
3025 if(pvBuf)
3026 {
3027 FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
3028 FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
3029 FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
3030 }
3031 cpfx += 3;
3032 point++;
3033 }
3034 }
3035 while(point <= outline->contours[contour] &&
3036 (outline->tags[point] & FT_Curve_Tag_On) ==
3037 (outline->tags[point-1] & FT_Curve_Tag_On));
3038 /* At the end of a contour Windows adds the start point,
3039 but only for Beziers and we've already done that.
3040 */
3041 if(point <= outline->contours[contour] &&
3042 outline->tags[point] & FT_Curve_Tag_On)
3043 {
3044 /* This is the closing pt of a bezier, but we've already
3045 added it, so just inc point and carry on */
3046 point++;
3047 }
3048 if(pvBuf)
3049 {
3050 ppc->wType = type;
3051 ppc->cpfx = cpfx;
3052 }
3053 needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3054 }
3055 if(pvBuf) pph->cb = needed - pph_start;
3056 }
3057 break;
3058 }
3059
3060 default:
3061 DPRINT1("Unsupported format %d\n", iFormat);
3062 if(pvBuf) ExFreePool(pvBuf);
3063 return GDI_ERROR;
3064 }
3065
3066 if (pvBuf)
3067 {
3068 Status = MmCopyToCaller(UnsafeBuf, pvBuf, cjBuf);
3069 if (! NT_SUCCESS(Status))
3070 {
3071 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3072 ExFreePool(pvBuf);
3073 return GDI_ERROR;
3074 }
3075 DPRINT("NtGdiGetGlyphOutline K -> U worked!\n");
3076 ExFreePool(pvBuf);
3077 }
3078
3079 DPRINT("NtGdiGetGlyphOutline END and needed %d\n", needed);
3080 return needed;
3081 }
3082
3083 DWORD
3084 STDCALL
3085 NtGdiGetKerningPairs(HDC hDC,
3086 DWORD NumPairs,
3087 LPKERNINGPAIR krnpair)
3088 {
3089 UNIMPLEMENTED;
3090 return 0;
3091 }
3092
3093 /*
3094 From "Undocumented Windows 2000 Secrets" Appendix B, Table B-2, page
3095 472, this is NtGdiGetOutlineTextMetricsInternalW.
3096 */
3097 UINT
3098 STDCALL
3099 NtGdiGetOutlineTextMetrics(HDC hDC,
3100 UINT Data,
3101 LPOUTLINETEXTMETRICW otm)
3102 {
3103 PDC dc;
3104 PTEXTOBJ TextObj;
3105 PFONTGDI FontGDI;
3106 HFONT hFont = 0;
3107 ULONG Size;
3108 OUTLINETEXTMETRICW *potm;
3109 NTSTATUS Status;
3110
3111 dc = DC_LockDc(hDC);
3112 if (dc == NULL)
3113 {
3114 SetLastWin32Error(ERROR_INVALID_HANDLE);
3115 return 0;
3116 }
3117 hFont = dc->w.hFont;
3118 TextObj = TEXTOBJ_LockText(hFont);
3119 DC_UnlockDc(dc);
3120 if (TextObj == NULL)
3121 {
3122 SetLastWin32Error(ERROR_INVALID_HANDLE);
3123 return 0;
3124 }
3125 FontGDI = ObjToGDI(TextObj->Font, FONT);
3126 TEXTOBJ_UnlockText(TextObj);
3127 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3128 if (!otm) return Size;
3129 if (Size > Data)
3130 {
3131 SetLastWin32Error(ERROR_INSUFFICIENT_BUFFER);
3132 return 0;
3133 }
3134 potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
3135 if (NULL == potm)
3136 {
3137 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3138 return 0;
3139 }
3140 IntGetOutlineTextMetrics(FontGDI, Size, potm);
3141 if (otm)
3142 {
3143 Status = MmCopyToCaller(otm, potm, Size);
3144 if (! NT_SUCCESS(Status))
3145 {
3146 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3147 ExFreePool(potm);
3148 return 0;
3149 }
3150 }
3151 ExFreePool(potm);
3152 return Size;
3153 }
3154
3155
3156 BOOL
3157 APIENTRY
3158 NtGdiGetRasterizerCaps(
3159 OUT LPRASTERIZER_STATUS praststat,
3160 IN ULONG cjBytes)
3161 {
3162 UNIMPLEMENTED;
3163 return FALSE;
3164 }
3165
3166
3167 /*
3168 Based on "Undocumented W2k Secrets", Table B-2, page 473.
3169 This function does not exist. See note in gdi32/objects/text.c
3170 GetTextCharset. This should be moved to include/win32k/ntgdibad.h.
3171 */
3172 UINT
3173 STDCALL
3174 NtGdiGetTextCharset(HDC hDC)
3175 {
3176 UNIMPLEMENTED;
3177 return 0;
3178 }
3179
3180 INT
3181 APIENTRY
3182 NtGdiGetTextCharsetInfo(
3183 IN HDC hdc,
3184 OUT OPTIONAL LPFONTSIGNATURE lpSig,
3185 IN DWORD dwFlags)
3186 {
3187 PDC Dc;
3188 UINT Ret = DEFAULT_CHARSET, i = 0, fs_fsCsb0 = 0;
3189 HFONT hFont;
3190 PTEXTOBJ TextObj;
3191 PFONTGDI FontGdi;
3192 FONTSIGNATURE fs;
3193 TT_OS2 *pOS2;
3194 FT_Face Face;
3195 NTSTATUS Status;
3196
3197 Dc = DC_LockDc(hdc);
3198 if (!Dc)
3199 {
3200 SetLastWin32Error(ERROR_INVALID_HANDLE);
3201 return Ret;
3202 }
3203 hFont = Dc->w.hFont;
3204 TextObj = TEXTOBJ_LockText(hFont);
3205 DC_UnlockDc( Dc );
3206 if ( TextObj == NULL)
3207 {
3208 SetLastWin32Error(ERROR_INVALID_HANDLE);
3209 return Ret;
3210 }
3211 FontGdi = ObjToGDI(TextObj->Font, FONT);
3212 Face = FontGdi->face;
3213 TEXTOBJ_UnlockText(TextObj);
3214 IntLockFreeType;
3215 pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3216 IntUnLockFreeType;
3217 memset(&fs, 0, sizeof(FONTSIGNATURE));
3218 if (NULL != pOS2)
3219 {
3220 fs.fsCsb[0] = pOS2->ulCodePageRange1;
3221 fs.fsCsb[1] = pOS2->ulCodePageRange2;
3222 fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3223 fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3224 fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3225 fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3226 fs_fsCsb0 = pOS2->ulCodePageRange1;
3227 if (pOS2->version == 0)
3228 {
3229 FT_UInt dummy;
3230
3231 if(FT_Get_First_Char( Face, &dummy ) < 0x100)
3232 fs_fsCsb0 |= 1;
3233 else
3234 fs_fsCsb0 |= 1L << 31;
3235 }
3236 }
3237 DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
3238 if (lpSig)
3239 {
3240 Status = MmCopyToCaller(lpSig, &fs, sizeof(FONTSIGNATURE));
3241 if (! NT_SUCCESS(Status))
3242 {
3243 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3244 return Ret;
3245 }
3246 }
3247 if (0 == fs_fsCsb0)
3248 { /* let's see if we can find any interesting cmaps */
3249 for (i = 0; i < Face->num_charmaps; i++)
3250 {
3251 switch (Face->charmaps[i]->encoding)
3252 {
3253 case ft_encoding_unicode:
3254 case ft_encoding_apple_roman:
3255 fs_fsCsb0 |= 1;
3256 break;
3257 case ft_encoding_symbol:
3258 fs_fsCsb0 |= 1L << 31;
3259 break;
3260 default:
3261 break;
3262 }
3263 }
3264 }
3265 while (0 == (fs_fsCsb0 >> i & 0x0001) && i < MAXTCIINDEX)
3266 {
3267 i++;
3268 }
3269 Ret = FontTci[i].ciCharset;
3270 DPRINT("CharSet %d\n",Ret);
3271 return Ret;
3272 }
3273
3274 static BOOL
3275 FASTCALL
3276 TextIntGetTextExtentPoint(PDC dc,
3277 PTEXTOBJ TextObj,
3278 LPCWSTR String,
3279 int Count,
3280 int MaxExtent,
3281 LPINT Fit,
3282 LPINT Dx,
3283 LPSIZE Size)
3284 {
3285 PFONTGDI FontGDI;
3286 FT_Face face;
3287 FT_GlyphSlot glyph;
3288 INT error, n, glyph_index, i, previous;
3289 ULONGLONG TotalWidth = 0;
3290 FT_CharMap charmap, found = NULL;
3291 BOOL use_kerning;
3292
3293 FontGDI = ObjToGDI(TextObj->Font, FONT);
3294
3295 face = FontGDI->face;
3296 if (NULL != Fit)
3297 {
3298 *Fit = 0;
3299 }
3300
3301 if (face->charmap == NULL)
3302 {
3303 DPRINT("WARNING: No charmap selected!\n");
3304 DPRINT("This font face has %d charmaps\n", face->num_charmaps);
3305
3306 for (n = 0; n < face->num_charmaps; n++)
3307 {
3308 charmap = face->charmaps[n];
3309 DPRINT("found charmap encoding: %u\n", charmap->encoding);
3310 if (charmap->encoding != 0)
3311 {
3312 found = charmap;
3313 break;
3314 }
3315 }
3316
3317 if (! found)
3318 {
3319 DPRINT1("WARNING: Could not find desired charmap!\n");
3320 }
3321
3322 IntLockFreeType;
3323 error = FT_Set_Charmap(face, found);
3324 IntUnLockFreeType;
3325 if (error)
3326 {
3327 DPRINT1("WARNING: Could not set the charmap!\n");
3328 }
3329 }
3330
3331 IntLockFreeType;
3332 error = FT_Set_Pixel_Sizes(face,
3333 TextObj->logfont.lfWidth,
3334 /* FIXME should set character height if neg */
3335 (TextObj->logfont.lfHeight < 0 ?
3336 - TextObj->logfont.lfHeight :
3337 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
3338 IntUnLockFreeType;
3339 if (error)
3340 {
3341 DPRINT1("Error in setting pixel sizes: %u\n", error);
3342 }
3343
3344 use_kerning = FT_HAS_KERNING(face);
3345 previous = 0;
3346
3347 for (i = 0; i < Count; i++)
3348 {
3349 IntLockFreeType;
3350 glyph_index = FT_Get_Char_Index(face, *String);
3351 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
3352 IntUnLockFreeType;
3353 if (error)
3354 {
3355 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
3356 }
3357 glyph = face->glyph;
3358
3359 /* retrieve kerning distance */
3360 if (use_kerning && previous && glyph_index)
3361 {
3362 FT_Vector delta;
3363 IntLockFreeType;
3364 FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
3365 IntUnLockFreeType;
3366 TotalWidth += delta.x;
3367 }
3368
3369 TotalWidth += glyph->advance.x;
3370
3371 if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
3372 {
3373 *Fit = i + 1;
3374 }
3375 if (NULL != Dx)
3376 {
3377 Dx[i] = (TotalWidth + 32) >> 6;
3378 }
3379
3380 previous = glyph_index;
3381 String++;
3382 }
3383
3384 Size->cx = (TotalWidth + 32) >> 6;
3385 Size->cy = (TextObj->logfont.lfHeight < 0 ? - TextObj->logfont.lfHeight : TextObj->logfont.lfHeight);
3386 Size->cy = EngMulDiv(Size->cy, IntGdiGetDeviceCaps(dc, LOGPIXELSY), 72);
3387
3388 return TRUE;
3389 }
3390
3391 BOOL
3392 STDCALL
3393 NtGdiGetTextExtentExPoint(HDC hDC,
3394 LPCWSTR UnsafeString,
3395 int Count,
3396 int MaxExtent,
3397 LPINT UnsafeFit,
3398 LPINT UnsafeDx,
3399 LPSIZE UnsafeSize)
3400 {
3401 PDC dc;
3402 LPWSTR String;
3403 SIZE Size;
3404 NTSTATUS Status;
3405 BOOLEAN Result;
3406 INT Fit;
3407 LPINT Dx;
3408 PTEXTOBJ TextObj;
3409
3410 if (Count < 0)
3411 {
3412 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3413 return FALSE;
3414 }
3415 if (0 == Count)
3416 {
3417 Size.cx = 0;
3418 Size.cy = 0;
3419 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
3420 if (! NT_SUCCESS(Status))
3421 {
3422 SetLastNtError(Status);
3423 return FALSE;
3424 }
3425 return TRUE;
3426 }
3427
3428 String = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), TAG_GDITEXT);
3429 if (NULL == String)
3430 {
3431 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3432 return FALSE;
3433 }
3434
3435 if (NULL != UnsafeDx)
3436 {
3437 Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
3438 if (NULL == Dx)
3439 {
3440 ExFreePool(String);
3441 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3442 return FALSE;
3443 }
3444 }
3445 else
3446 {
3447 Dx = NULL;
3448 }
3449
3450 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
3451 if (! NT_SUCCESS(Status))
3452 {
3453 if (NULL != Dx)
3454 {
3455 ExFreePool(Dx);
3456 }
3457 ExFreePool(String);
3458 SetLastNtError(Status);
3459 return FALSE;
3460 }
3461
3462 dc = DC_LockDc(hDC);
3463 if (NULL == dc)
3464 {
3465 if (NULL != Dx)
3466 {
3467 ExFreePool(Dx);
3468 }
3469 ExFreePool(String);
3470 SetLastWin32Error(ERROR_INVALID_HANDLE);
3471 return FALSE;
3472 }
3473 TextObj = TEXTOBJ_LockText(dc->w.hFont);
3474 if ( TextObj )
3475 {
3476 Result = TextIntGetTextExtentPoint(dc, TextObj, String, Count, MaxExtent,
3477 NULL == UnsafeFit ? NULL : &Fit, Dx, &Size);
3478 }
3479 else
3480 Result = FALSE;
3481 TEXTOBJ_UnlockText(TextObj);
3482 DC_UnlockDc(dc);
3483
3484 ExFreePool(String);
3485 if (! Result)
3486 {
3487 if (NULL != Dx)
3488 {
3489 ExFreePool(Dx);
3490 }
3491 return FALSE;
3492 }
3493
3494 if (NULL != UnsafeFit)
3495 {
3496 Status = MmCopyToCaller(UnsafeFit, &Fit, sizeof(INT));
3497 if (! NT_SUCCESS(Status))
3498 {
3499 if (NULL != Dx)
3500 {
3501 ExFreePool(Dx);
3502 }
3503 SetLastNtError(Status);
3504 return FALSE;
3505 }
3506 }
3507
3508 if (NULL != UnsafeDx)
3509 {
3510 Status = MmCopyToCaller(UnsafeDx, Dx, Count * sizeof(INT));
3511 if (! NT_SUCCESS(Status))
3512 {
3513 if (NULL != Dx)
3514 {
3515 ExFreePool(Dx);
3516 }
3517 SetLastNtError(Status);
3518 return FALSE;
3519 }
3520 }
3521 if (NULL != Dx)
3522 {
3523 ExFreePool(Dx);
3524 }
3525
3526 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
3527 if (! NT_SUCCESS(Status))
3528 {
3529 SetLastNtError(Status);
3530 return FALSE;
3531 }
3532
3533 return TRUE;
3534 }
3535
3536 BOOL
3537 STDCALL
3538 NtGdiGetTextExtent(HDC hdc,
3539 LPWSTR lpwsz,
3540 INT cwc,
3541 LPSIZE psize,
3542 UINT flOpts)
3543 {
3544 return NtGdiGetTextExtentExPoint(hdc, lpwsz, cwc, 0, NULL, NULL, psize);
3545 }
3546
3547 BOOL
3548 STDCALL
3549 NtGdiGetTextExtentPoint32(HDC hDC,
3550 LPCWSTR UnsafeString,
3551 int Count,
3552 LPSIZE UnsafeSize)
3553 {
3554 PDC dc;
3555 LPWSTR String;
3556 SIZE Size;
3557 NTSTATUS Status;
3558 BOOLEAN Result;
3559 PTEXTOBJ TextObj;
3560
3561 if (Count < 0)
3562 {
3563 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3564 return FALSE;
3565 }
3566 if (0 == Count)
3567 {
3568 Size.cx = 0;
3569 Size.cy = 0;
3570 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
3571 if (! NT_SUCCESS(Status))
3572 {
3573 SetLastNtError(Status);
3574 return FALSE;
3575 }
3576 return TRUE;
3577 }
3578
3579 String = ExAllocatePool(PagedPool, Count * sizeof(WCHAR));
3580 if (NULL == String)
3581 {
3582 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3583 return FALSE;
3584 }
3585
3586 Status = MmCopyFromCaller(String, UnsafeString, Count * sizeof(WCHAR));
3587 if (! NT_SUCCESS(Status))
3588 {
3589 ExFreePool(String);
3590 SetLastNtError(Status);
3591 return FALSE;
3592 }
3593
3594 dc = DC_LockDc(hDC);
3595 if (NULL == dc)
3596 {
3597 ExFreePool(String);
3598 SetLastWin32Error(ERROR_INVALID_HANDLE);
3599 return FALSE;
3600 }
3601 TextObj = TEXTOBJ_LockText(dc->w.hFont);
3602 if ( TextObj != NULL )
3603 {
3604 Result = TextIntGetTextExtentPoint (
3605 dc, TextObj, String, Count, 0, NULL, NULL, &Size);
3606 TEXTOBJ_UnlockText(TextObj);
3607 }
3608 else
3609 Result = FALSE;
3610 DC_UnlockDc(dc);
3611
3612 ExFreePool(String);
3613 if (! Result)
3614 {
3615 return FALSE;
3616 }
3617
3618 Status = MmCopyToCaller(UnsafeSize, &Size, sizeof(SIZE));
3619 if (! NT_SUCCESS(Status))
3620 {
3621 SetLastNtError(Status);
3622 return FALSE;
3623 }
3624
3625 return TRUE;
3626 }
3627
3628 INT STDCALL
3629 NtGdiGetTextFace(HDC hDC, INT Count, LPWSTR FaceName)
3630 {
3631 PDC Dc;
3632 HFONT hFont;
3633 PTEXTOBJ TextObj;
3634 NTSTATUS Status;
3635
3636 Dc = DC_LockDc(hDC);
3637 if (Dc == NULL)
3638 {
3639 SetLastWin32Error(ERROR_INVALID_HANDLE);
3640 return FALSE;
3641 }
3642 hFont = Dc->w.hFont;
3643 DC_UnlockDc(Dc);
3644
3645 TextObj = TEXTOBJ_LockText(hFont);
3646 ASSERT(TextObj != NULL);
3647 Count = min(Count, wcslen(TextObj->logfont.lfFaceName));
3648 Status = MmCopyToCaller(FaceName, TextObj->logfont.lfFaceName, Count * sizeof(WCHAR));
3649 TEXTOBJ_UnlockText(TextObj);
3650 if (!NT_SUCCESS(Status))
3651 {
3652 SetLastNtError(Status);
3653 return 0;
3654 }
3655
3656 return Count;
3657 }
3658
3659 BOOL
3660 STDCALL
3661 NtGdiGetTextMetrics(HDC hDC,
3662 LPTEXTMETRICW tm)
3663 {
3664 PDC dc;
3665 PTEXTOBJ TextObj;
3666 PFONTGDI FontGDI;
3667 NTSTATUS Status = STATUS_SUCCESS;
3668 TEXTMETRICW SafeTm;
3669 FT_Face Face;
3670 TT_OS2 *pOS2;
3671 TT_HoriHeader *pHori;
3672 ULONG Error;
3673
3674 if (NULL == tm)
3675 {
3676 SetLastWin32Error(STATUS_INVALID_PARAMETER);
3677 return FALSE;
3678 }
3679
3680 if(!(dc = DC_LockDc(hDC)))
3681 {
3682 SetLastWin32Error(ERROR_INVALID_HANDLE);
3683 return FALSE;
3684 }
3685
3686 TextObj = TEXTOBJ_LockText(dc->w.hFont);
3687 if (NULL != TextObj)
3688 {
3689 FontGDI = ObjToGDI(TextObj->Font, FONT);
3690
3691 Face = FontGDI->face;
3692 IntLockFreeType;
3693 Error = FT_Set_Pixel_Sizes(Face,
3694 TextObj->logfont.lfWidth,
3695 /* FIXME should set character height if neg */
3696 (TextObj->logfont.lfHeight < 0 ?
3697 - TextObj->logfont.lfHeight :
3698 TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
3699 IntUnLockFreeType;
3700 if (0 != Error)
3701 {
3702 DPRINT1("Error in setting pixel sizes: %u\n", Error);
3703 Status = STATUS_UNSUCCESSFUL;
3704 }
3705 else
3706 {
3707 memcpy(&SafeTm, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
3708
3709 Status = STATUS_SUCCESS;
3710 IntLockFreeType;
3711 pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
3712 if (NULL == pOS2)
3713 {
3714 DPRINT1("Can't find OS/2 table - not TT font?\n");
3715 Status = STATUS_INTERNAL_ERROR;
3716 }
3717
3718 pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
3719 if (NULL == pHori)
3720 {
3721 DPRINT1("Can't find HHEA table - not TT font?\n");
3722 Status = STATUS_INTERNAL_ERROR;
3723 }
3724
3725 IntUnLockFreeType;
3726
3727 if (NT_SUCCESS(Status))
3728 {
3729 FillTM(&SafeTm, FontGDI->face, pOS2, pHori);
3730 Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
3731 }
3732 }
3733 TEXTOBJ_UnlockText(TextObj);
3734 }
3735 else
3736 {
3737 Status = STATUS_INVALID_HANDLE;
3738 }
3739 DC_UnlockDc(dc);
3740
3741 if(!NT_SUCCESS(Status))
3742 {
3743 SetLastNtError(Status);
3744 return FALSE;
3745 }
3746
3747 return TRUE;
3748 }
3749
3750 BOOL
3751 STDCALL
3752 NtGdiPolyTextOut(HDC hDC,
3753 CONST LPPOLYTEXTW txt,
3754 int Count)
3755 {
3756 UNIMPLEMENTED;
3757 return FALSE;
3758 }
3759
3760 BOOL
3761 STDCALL
3762 NtGdiRemoveFontResource(LPCWSTR FileName)
3763 {
3764 DPRINT1("NtGdiRemoveFontResource is UNIMPLEMENTED\n");
3765 return FALSE;
3766 }
3767
3768 DWORD
3769 STDCALL
3770 NtGdiSetMapperFlags(HDC hDC,
3771 DWORD Flag)
3772 {
3773 UNIMPLEMENTED;
3774 return 0;
3775 }
3776
3777 UINT
3778 STDCALL
3779 NtGdiSetTextAlign(HDC hDC,
3780 UINT Mode)
3781 {
3782 UINT prevAlign;
3783 DC *dc;
3784
3785 dc = DC_LockDc(hDC);
3786 if (!dc)
3787 {
3788 SetLastWin32Error(ERROR_INVALID_HANDLE);
3789 return GDI_ERROR;
3790 }
3791 prevAlign = dc->w.textAlign;
3792 dc->w.textAlign = Mode;
3793 DC_UnlockDc( dc );
3794 return prevAlign;
3795 }
3796
3797 COLORREF
3798 STDCALL
3799 NtGdiSetTextColor(HDC hDC,
3800 COLORREF color)
3801 {
3802 COLORREF oldColor;
3803 PDC dc = DC_LockDc(hDC);
3804 HBRUSH hBrush;
3805
3806 if (!dc)
3807 {
3808 SetLastWin32Error(ERROR_INVALID_HANDLE);
3809 return CLR_INVALID;
3810 }
3811
3812 oldColor = dc->w.textColor;
3813 dc->w.textColor = color;
3814 hBrush = dc->w.hBrush;
3815 DC_UnlockDc( dc );
3816 NtGdiSelectObject(hDC, hBrush);
3817 return oldColor;
3818 }
3819
3820 BOOL
3821 STDCALL
3822 NtGdiSetTextJustification(HDC hDC,
3823 int BreakExtra,
3824 int BreakCount)
3825 {
3826 UNIMPLEMENTED;
3827 return FALSE;
3828 }
3829
3830 BOOL STDCALL
3831 NtGdiTextOut(
3832 HDC hDC,
3833 INT XStart,
3834 INT YStart,
3835 LPCWSTR String,
3836 INT Count)
3837 {
3838 return NtGdiExtTextOut(hDC, XStart, YStart, 0, NULL, String, Count, NULL);
3839 }
3840
3841 DWORD STDCALL
3842 NtGdiGetFontData(
3843 HDC hDC,
3844 DWORD Table,
3845 DWORD Offset,
3846 LPVOID Buffer,
3847 DWORD Size)
3848 {
3849 PDC Dc;
3850 HFONT hFont;
3851 PTEXTOBJ TextObj;
3852 PFONTGDI FontGdi;
3853 DWORD Result = GDI_ERROR;
3854
3855 Dc = DC_LockDc(hDC);
3856 if (Dc == NULL)
3857 {
3858 SetLastWin32Error(ERROR_INVALID_HANDLE);
3859 return GDI_ERROR;
3860 }
3861 hFont = Dc->w.hFont;
3862 TextObj = TEXTOBJ_LockText(hFont);
3863 DC_UnlockDc(Dc);
3864
3865 if (TextObj == NULL)
3866 {
3867 SetLastWin32Error(ERROR_INVALID_HANDLE);
3868 return GDI_ERROR;
3869 }
3870
3871 FontGdi = ObjToGDI(TextObj->Font, FONT);
3872
3873 IntLockFreeType;
3874
3875 if (FT_IS_SFNT(FontGdi->face))
3876 {
3877 if (Table)
3878 Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
3879 (Table << 8 & 0xFF0000);
3880
3881 if (Buffer == NULL)
3882 Size = 0;
3883
3884 if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
3885 Result = Size;
3886 }
3887
3888 IntUnLockFreeType;
3889
3890 TEXTOBJ_UnlockText(TextObj);
3891
3892 return Result;
3893 }
3894
3895 static UINT FASTCALL
3896 GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
3897 {
3898 ANSI_STRING EntryFaceNameA;
3899 UNICODE_STRING EntryFaceNameW;
3900 unsigned Size;
3901 OUTLINETEXTMETRICW *Otm;
3902 LONG WeightDiff;
3903 NTSTATUS Status;
3904 UINT Score = 1;
3905
3906 RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
3907 Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
3908 if (NT_SUCCESS(Status))
3909 {
3910 if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
3911 {
3912 EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
3913 EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
3914 }
3915 if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
3916 {
3917 Score += 49;
3918 }
3919 RtlFreeUnicodeString(&EntryFaceNameW);
3920 }
3921
3922 Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
3923 Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
3924 if (NULL == Otm)
3925 {
3926 return Score;
3927 }
3928 IntGetOutlineTextMetrics(FontGDI, Size, Otm);
3929
3930 if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
3931 (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
3932 {
3933 Score += 25;
3934 }
3935 if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
3936 {
3937 WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
3938 }
3939 else
3940 {
3941 WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
3942 }
3943 Score += (1000 - WeightDiff) / (1000 / 25);
3944
3945 ExFreePool(Otm);
3946
3947 return Score;
3948 }
3949
3950 static __inline VOID
3951 FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
3952 PUNICODE_STRING FaceName, PLIST_ENTRY Head)
3953 {
3954 PLIST_ENTRY Entry;
3955 PFONT_ENTRY CurrentEntry;
3956 FONTGDI *FontGDI;
3957 UINT Score;
3958
3959 Entry = Head->Flink;
3960 while (Entry != Head)
3961 {
3962 CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
3963
3964 FontGDI = CurrentEntry->Font;
3965 ASSERT(FontGDI);
3966
3967 Score = GetFontScore(LogFont, FaceName, FontGDI);
3968 if (*MatchScore == 0 || *MatchScore < Score)
3969 {
3970 *FontObj = GDIToObj(FontGDI, FONT);
3971 *MatchScore = Score;
3972 }
3973 Entry = Entry->Flink;
3974 }
3975 }
3976
3977 static __inline BOOLEAN
3978 SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
3979 LPCWSTR Key)
3980 {
3981 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
3982 NTSTATUS Status;
3983 UNICODE_STRING Value;
3984
3985 RtlInitUnicodeString(&Value, NULL);
3986
3987 QueryTable[0].QueryRoutine = NULL;
3988 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
3989 RTL_QUERY_REGISTRY_REQUIRED;
3990 QueryTable[0].Name = FaceName->Buffer;
3991 QueryTable[0].EntryContext = &Value;
3992 QueryTable[0].DefaultType = REG_NONE;
3993 QueryTable[0].DefaultData = NULL;
3994 QueryTable[0].DefaultLength = 0;
3995
3996 QueryTable[1].QueryRoutine = NULL;
3997 QueryTable[1].Name = NULL;
3998
3999 Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
4000 Key,
4001 QueryTable,
4002 NULL,
4003 NULL);
4004 if (NT_SUCCESS(Status))
4005 {
4006 RtlFreeUnicodeString(FaceName);
4007 *FaceName = Value;
4008 }
4009
4010 return NT_SUCCESS(Status);
4011 }
4012
4013 static __inline void
4014 SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
4015 {
4016 if (10 < Level) /* Enough is enough */
4017 {
4018 return;
4019 }
4020
4021 if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
4022 SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
4023 {
4024 SubstituteFontFamily(FaceName, Level + 1);
4025 }
4026 }
4027
4028 NTSTATUS FASTCALL
4029 TextIntRealizeFont(HFONT FontHandle)
4030 {
4031 NTSTATUS Status = STATUS_SUCCESS;
4032 PTEXTOBJ TextObj;
4033 UNICODE_STRING FaceName;
4034 PW32PROCESS Win32Process;
4035 UINT MatchScore;
4036
4037 TextObj = TEXTOBJ_LockText(FontHandle);
4038 if (NULL == TextObj)
4039 {
4040 return STATUS_INVALID_HANDLE;
4041 }
4042
4043 if (TextObj->Initialized)
4044 {
4045 TEXTOBJ_UnlockText(TextObj);
4046 return STATUS_SUCCESS;
4047 }
4048
4049 if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.lfFaceName))
4050 {
4051 TEXTOBJ_UnlockText(TextObj);
4052 return STATUS_NO_MEMORY;
4053 }
4054 SubstituteFontFamily(&FaceName, 0);
4055 MatchScore = 0;
4056 TextObj->Font = NULL;
4057
4058 /* First search private fonts */
4059 Win32Process = PsGetCurrentProcessWin32Process();
4060 IntLockProcessPrivateFonts(Win32Process);
4061 FindBestFontFromList(&TextObj->Font, &MatchScore,
4062 &TextObj->logfont, &FaceName,
4063 &Win32Process->PrivateFontListHead);
4064 IntUnLockProcessPrivateFonts(Win32Process);
4065
4066 /* Search system fonts */
4067 IntLockGlobalFonts;
4068 FindBestFontFromList(&TextObj->Font, &MatchScore,
4069 &TextObj->logfont, &FaceName,
4070 &FontListHead);
4071 IntUnLockGlobalFonts;
4072
4073 if (NULL == TextObj->Font)
4074 {
4075 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
4076 TextObj->logfont.lfFaceName);
4077 Status = STATUS_NOT_FOUND;
4078 }
4079 else
4080 {
4081 TextObj->Initialized = TRUE;
4082 Status = STATUS_SUCCESS;
4083 }
4084
4085 RtlFreeUnicodeString(&FaceName);
4086 TEXTOBJ_UnlockText(TextObj);
4087
4088 ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
4089
4090 return Status;
4091 }
4092
4093 INT FASTCALL
4094 FontGetObject(PTEXTOBJ Font, INT Count, PVOID Buffer)
4095 {
4096 if( Buffer == NULL ) return sizeof(LOGFONTW);
4097
4098 /* fixme SetLastWin32Error(ERROR_BUFFER_OVERFLOW); in count<0*/
4099 if (Count < sizeof(LOGFONTW)) return 0;
4100 if (Count > sizeof(LOGFONTW)) Count = sizeof(LOGFONTW);
4101
4102 RtlCopyMemory(Buffer, &Font->logfont, sizeof(LOGFONTW));
4103 return sizeof(LOGFONTW);
4104 }
4105
4106
4107 /* Remove this HAX! after the below function is done in GDI32.DLL! */
4108 INT
4109 STDCALL
4110 NtGdiGetSetTextCharExtra( HDC hDC, INT CharExtra, BOOL Set)
4111 {
4112 /* Ulta-Ugly Hax! */
4113 INT Ret = 0x80000000;
4114 DPRINT("TextCharacterExtra %d", CharExtra);
4115 PDC dc = DC_LockDc ( hDC );
4116 if (!dc)
4117 {
4118 SetLastWin32Error(ERROR_INVALID_HANDLE);
4119 return Ret;
4120 }
4121 Ret = dc->w.charExtra;
4122 if( Set ) dc->w.charExtra = CharExtra;
4123 DC_UnlockDc(dc);
4124 return (Ret);
4125 }
4126
4127 /* EOF */