2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/objects/freetype.c
5 * PURPOSE: FreeType font engine interface
6 * PROGRAMMER: Copyright 2001 Huw D M Davies for CodeWeavers.
7 * Copyright 2006 Dmitry Timoshkov for CodeWeavers.
10 /** Includes ******************************************************************/
18 #define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
19 ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
20 ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
25 typedef struct _FONT_ENTRY
29 UNICODE_STRING FaceName
;
31 } FONT_ENTRY
, *PFONT_ENTRY
;
33 /* The FreeType library is not thread safe, so we have
34 to serialize access to it */
35 static PFAST_MUTEX FreeTypeLock
;
37 static LIST_ENTRY FontListHead
;
38 static PFAST_MUTEX FontListLock
;
39 static BOOL RenderingEnabled
= TRUE
;
41 #define IntLockGlobalFonts \
42 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FontListLock)
44 #define IntUnLockGlobalFonts \
45 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
47 #define IntLockFreeType \
48 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
50 #define IntUnLockFreeType \
51 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock)
53 #define MAX_FONT_CACHE 256
55 typedef struct _FONT_CACHE_ENTRY
60 FT_BitmapGlyph BitmapGlyph
;
62 MATRIX mxWorldToDevice
;
63 } FONT_CACHE_ENTRY
, *PFONT_CACHE_ENTRY
;
64 static LIST_ENTRY FontCacheListHead
;
65 static UINT FontCacheNumEntries
;
67 static PWCHAR ElfScripts
[32] = /* These are in the order of the fsCsb[0] bits */
77 L
"Vietnamese", /* 08 */
78 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, /* 15 */
86 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
91 * For TranslateCharsetInfo
94 #define MAXTCIINDEX 32
95 static const CHARSETINFO FontTci
[MAXTCIINDEX
] =
98 { ANSI_CHARSET
, 1252, {{0,0,0,0},{FS_LATIN1
,0}} },
99 { EASTEUROPE_CHARSET
, 1250, {{0,0,0,0},{FS_LATIN2
,0}} },
100 { RUSSIAN_CHARSET
, 1251, {{0,0,0,0},{FS_CYRILLIC
,0}} },
101 { GREEK_CHARSET
, 1253, {{0,0,0,0},{FS_GREEK
,0}} },
102 { TURKISH_CHARSET
, 1254, {{0,0,0,0},{FS_TURKISH
,0}} },
103 { HEBREW_CHARSET
, 1255, {{0,0,0,0},{FS_HEBREW
,0}} },
104 { ARABIC_CHARSET
, 1256, {{0,0,0,0},{FS_ARABIC
,0}} },
105 { BALTIC_CHARSET
, 1257, {{0,0,0,0},{FS_BALTIC
,0}} },
106 { VIETNAMESE_CHARSET
, 1258, {{0,0,0,0},{FS_VIETNAMESE
,0}} },
107 /* reserved by ANSI */
108 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
109 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
110 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
111 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
112 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
113 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
114 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
116 { THAI_CHARSET
, 874, {{0,0,0,0},{FS_THAI
,0}} },
117 { SHIFTJIS_CHARSET
, 932, {{0,0,0,0},{FS_JISJAPAN
,0}} },
118 { GB2312_CHARSET
, 936, {{0,0,0,0},{FS_CHINESESIMP
,0}} },
119 { HANGEUL_CHARSET
, 949, {{0,0,0,0},{FS_WANSUNG
,0}} },
120 { CHINESEBIG5_CHARSET
, 950, {{0,0,0,0},{FS_CHINESETRAD
,0}} },
121 { JOHAB_CHARSET
, 1361, {{0,0,0,0},{FS_JOHAB
,0}} },
122 /* Reserved for alternate ANSI and OEM */
123 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
124 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
125 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
126 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
127 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
128 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
129 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
130 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
131 /* Reserved for system */
132 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
133 { SYMBOL_CHARSET
, CP_SYMBOL
, {{0,0,0,0},{FS_SYMBOL
,0}} }
137 InitFontSupport(VOID
)
141 InitializeListHead(&FontListHead
);
142 InitializeListHead(&FontCacheListHead
);
143 FontCacheNumEntries
= 0;
144 /* Fast Mutexes must be allocated from non paged pool */
145 FontListLock
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(FAST_MUTEX
), TAG_INTERNAL_SYNC
);
146 ExInitializeFastMutex(FontListLock
);
147 FreeTypeLock
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(FAST_MUTEX
), TAG_INTERNAL_SYNC
);
148 ExInitializeFastMutex(FreeTypeLock
);
150 ulError
= FT_Init_FreeType(&library
);
153 DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError
);
157 IntLoadSystemFonts();
163 FtSetCoordinateTransform(
170 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
172 FLOATOBJ_MulLong(&efTemp
, 0x00010000);
173 ftmatrix
.xx
= FLOATOBJ_GetLong(&efTemp
);
176 FLOATOBJ_MulLong(&efTemp
, 0x00010000);
177 ftmatrix
.xy
= FLOATOBJ_GetLong(&efTemp
);
180 FLOATOBJ_MulLong(&efTemp
, 0x00010000);
181 ftmatrix
.yx
= FLOATOBJ_GetLong(&efTemp
);
184 FLOATOBJ_MulLong(&efTemp
, 0x00010000);
185 ftmatrix
.yy
= FLOATOBJ_GetLong(&efTemp
);
187 /* Set the transformation matrix */
188 FT_Set_Transform(face
, &ftmatrix
, 0);
194 * Search the system font directory and adds each font found.
198 IntLoadSystemFonts(VOID
)
200 OBJECT_ATTRIBUTES ObjectAttributes
;
201 UNICODE_STRING Directory
, SearchPattern
, FileName
, TempString
;
202 IO_STATUS_BLOCK Iosb
;
205 PFILE_DIRECTORY_INFORMATION DirInfo
;
206 BOOLEAN bRestartScan
= TRUE
;
209 RtlInitUnicodeString(&Directory
, L
"\\SystemRoot\\Fonts\\");
210 /* FIXME: Add support for other font types */
211 RtlInitUnicodeString(&SearchPattern
, L
"*.ttf");
213 InitializeObjectAttributes(
216 OBJ_CASE_INSENSITIVE
,
222 SYNCHRONIZE
| FILE_LIST_DIRECTORY
,
225 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
226 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_DIRECTORY_FILE
);
228 if (NT_SUCCESS(Status
))
230 DirInfoBuffer
= ExAllocatePoolWithTag(PagedPool
, 0x4000, TAG_FONT
);
231 if (DirInfoBuffer
== NULL
)
237 FileName
.Buffer
= ExAllocatePoolWithTag(PagedPool
, MAX_PATH
* sizeof(WCHAR
), TAG_FONT
);
238 if (FileName
.Buffer
== NULL
)
240 ExFreePoolWithTag(DirInfoBuffer
, TAG_FONT
);
245 FileName
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
249 Status
= ZwQueryDirectoryFile(
257 FileDirectoryInformation
,
262 if (!NT_SUCCESS(Status
) || Status
== STATUS_NO_MORE_FILES
)
267 DirInfo
= (PFILE_DIRECTORY_INFORMATION
)DirInfoBuffer
;
270 TempString
.Buffer
= DirInfo
->FileName
;
272 TempString
.MaximumLength
= DirInfo
->FileNameLength
;
273 RtlCopyUnicodeString(&FileName
, &Directory
);
274 RtlAppendUnicodeStringToString(&FileName
, &TempString
);
275 IntGdiAddFontResource(&FileName
, 0);
276 if (DirInfo
->NextEntryOffset
== 0)
278 DirInfo
= (PFILE_DIRECTORY_INFORMATION
)((ULONG_PTR
)DirInfo
+ DirInfo
->NextEntryOffset
);
281 bRestartScan
= FALSE
;
284 ExFreePoolWithTag(FileName
.Buffer
, TAG_FONT
);
285 ExFreePoolWithTag(DirInfoBuffer
, TAG_FONT
);
292 * IntGdiAddFontResource
294 * Adds the font resource from the specified file to the system.
298 IntGdiAddFontResource(PUNICODE_STRING FileName
, DWORD Characteristics
)
302 HANDLE FileHandle
, KeyHandle
;
303 OBJECT_ATTRIBUTES ObjectAttributes
;
305 IO_STATUS_BLOCK Iosb
;
308 ANSI_STRING AnsiFaceName
;
312 LARGE_INTEGER SectionSize
;
313 UNICODE_STRING FontRegPath
= RTL_CONSTANT_STRING(L
"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
315 /* Open the font file */
317 InitializeObjectAttributes(&ObjectAttributes
, FileName
, 0, NULL
, NULL
);
320 FILE_GENERIC_READ
| SYNCHRONIZE
,
324 FILE_SYNCHRONOUS_IO_NONALERT
);
326 if (!NT_SUCCESS(Status
))
328 DPRINT("Could not load font file: %wZ\n", FileName
);
332 SectionSize
.QuadPart
= 0LL;
333 Status
= MmCreateSection(&SectionObject
, SECTION_ALL_ACCESS
,
334 NULL
, &SectionSize
, PAGE_READONLY
,
335 SEC_COMMIT
, FileHandle
, NULL
);
336 if (!NT_SUCCESS(Status
))
338 DPRINT("Could not map file: %wZ\n", FileName
);
345 Status
= MmMapViewInSystemSpace(SectionObject
, &Buffer
, &ViewSize
);
346 if (!NT_SUCCESS(Status
))
348 DPRINT("Could not map file: %wZ\n", FileName
);
349 ObDereferenceObject(SectionObject
);
354 Error
= FT_New_Memory_Face(
361 ObDereferenceObject(SectionObject
);
365 if (Error
== FT_Err_Unknown_File_Format
)
366 DPRINT("Unknown font file format\n");
368 DPRINT("Error reading font file (error code: %d)\n", Error
);
372 Entry
= ExAllocatePoolWithTag(PagedPool
, sizeof(FONT_ENTRY
), TAG_FONT
);
376 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
380 FontGDI
= EngAllocMem(FL_ZERO_MEMORY
, sizeof(FONTGDI
), GDITAG_RFONT
);
384 ExFreePoolWithTag(Entry
, TAG_FONT
);
385 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
389 FontGDI
->Filename
= ExAllocatePoolWithTag(PagedPool
, FileName
->Length
+ sizeof(WCHAR
), GDITAG_PFF
);
390 if (FontGDI
->Filename
== NULL
)
394 ExFreePoolWithTag(Entry
, TAG_FONT
);
395 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
398 RtlCopyMemory(FontGDI
->Filename
, FileName
->Buffer
, FileName
->Length
);
399 FontGDI
->Filename
[FileName
->Length
/ sizeof(WCHAR
)] = L
'\0';
400 FontGDI
->face
= Face
;
402 DPRINT("Font loaded: %s (%s)\n", Face
->family_name
, Face
->style_name
);
403 DPRINT("Num glyphs: %d\n", Face
->num_glyphs
);
405 /* Add this font resource to the font table */
407 Entry
->Font
= FontGDI
;
408 Entry
->NotEnum
= (Characteristics
& FR_NOT_ENUM
);
409 RtlInitAnsiString(&AnsiFaceName
, (LPSTR
)Face
->family_name
);
410 RtlAnsiStringToUnicodeString(&Entry
->FaceName
, &AnsiFaceName
, TRUE
);
412 if (Characteristics
& FR_PRIVATE
)
414 PPROCESSINFO Win32Process
= PsGetCurrentProcessWin32Process();
415 IntLockProcessPrivateFonts(Win32Process
);
416 InsertTailList(&Win32Process
->PrivateFontListHead
, &Entry
->ListEntry
);
417 IntUnLockProcessPrivateFonts(Win32Process
);
422 InsertTailList(&FontListHead
, &Entry
->ListEntry
);
423 InitializeObjectAttributes(&ObjectAttributes
, &FontRegPath
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
424 Status
= ZwOpenKey(&KeyHandle
, KEY_WRITE
, &ObjectAttributes
);
425 if (NT_SUCCESS(Status
))
427 LPWSTR pName
= wcsrchr(FileName
->Buffer
, L
'\\');
431 ZwSetValueKey(KeyHandle
, &Entry
->FaceName
, 0, REG_SZ
, pName
, (wcslen(pName
) + 1) * sizeof(WCHAR
));
435 IntUnLockGlobalFonts
;
441 IntIsFontRenderingEnabled(VOID
)
443 BOOL Ret
= RenderingEnabled
;
446 hDC
= IntGetScreenDC();
448 Ret
= (NtGdiGetDeviceCaps(hDC
, BITSPIXEL
) > 8) && RenderingEnabled
;
454 IntEnableFontRendering(BOOL Enable
)
456 RenderingEnabled
= Enable
;
459 FT_Render_Mode FASTCALL
460 IntGetFontRenderMode(LOGFONTW
*logfont
)
462 switch (logfont
->lfQuality
)
464 case NONANTIALIASED_QUALITY
:
465 return FT_RENDER_MODE_MONO
;
467 return FT_RENDER_MODE_LIGHT
;
468 /* case CLEARTYPE_QUALITY:
469 return FT_RENDER_MODE_LCD; */
471 return FT_RENDER_MODE_NORMAL
;
476 TextIntCreateFontIndirect(CONST LPLOGFONTW lf
, HFONT
*NewFont
)
480 plfont
= LFONT_AllocFontWithHandle();
483 return STATUS_NO_MEMORY
;
486 ExInitializePushLock(&plfont
->lock
);
487 *NewFont
= plfont
->BaseObject
.hHmgr
;
488 RtlCopyMemory(&plfont
->logfont
.elfEnumLogfontEx
.elfLogFont
, lf
, sizeof(LOGFONTW
));
489 if (lf
->lfEscapement
!= lf
->lfOrientation
)
491 /* This should really depend on whether GM_ADVANCED is set */
492 plfont
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfOrientation
=
493 plfont
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfEscapement
;
495 LFONT_UnlockFont(plfont
);
497 return STATUS_SUCCESS
;
500 /*************************************************************************
501 * TranslateCharsetInfo
503 * Fills a CHARSETINFO structure for a character set, code page, or
504 * font. This allows making the correspondance between different labelings
505 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
506 * of the same encoding.
508 * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
509 * only one codepage should be set in *Src.
512 * TRUE on success, FALSE on failure.
515 static BOOLEAN APIENTRY
516 IntTranslateCharsetInfo(PDWORD Src
, /* [in]
517 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
518 if flags == TCI_SRCCHARSET: a character set value
519 if flags == TCI_SRCCODEPAGE: a code page value */
520 LPCHARSETINFO Cs
, /* [out] structure to receive charset information */
521 DWORD Flags
/* [in] determines interpretation of lpSrc */)
528 while (0 == (*Src
>> Index
& 0x0001) && Index
< MAXTCIINDEX
)
533 case TCI_SRCCODEPAGE
:
534 while ( *Src
!= FontTci
[Index
].ciACP
&& Index
< MAXTCIINDEX
)
540 while ( *Src
!= FontTci
[Index
].ciCharset
&& Index
< MAXTCIINDEX
)
549 if (Index
>= MAXTCIINDEX
|| DEFAULT_CHARSET
== FontTci
[Index
].ciCharset
)
554 RtlCopyMemory(Cs
, &FontTci
[Index
], sizeof(CHARSETINFO
));
560 static BOOL
face_has_symbol_charmap(FT_Face ft_face
)
564 for(i
= 0; i
< ft_face
->num_charmaps
; i
++)
566 if(ft_face
->charmaps
[i
]->encoding
== FT_ENCODING_MS_SYMBOL
)
573 FillTM(TEXTMETRICW
*TM
, PFONTGDI FontGDI
, TT_OS2
*pOS2
, TT_HoriHeader
*pHori
, FT_WinFNT_HeaderRec
*pWin
)
575 FT_Fixed XScale
, YScale
;
577 FT_Face Face
= FontGDI
->face
;
579 XScale
= Face
->size
->metrics
.x_scale
;
580 YScale
= Face
->size
->metrics
.y_scale
;
584 TM
->tmHeight
= pWin
->pixel_height
;
585 TM
->tmAscent
= pWin
->ascent
;
586 TM
->tmDescent
= TM
->tmHeight
- TM
->tmAscent
;
587 TM
->tmInternalLeading
= pWin
->internal_leading
;
588 TM
->tmExternalLeading
= pWin
->external_leading
;
589 TM
->tmAveCharWidth
= pWin
->avg_width
;
590 TM
->tmMaxCharWidth
= pWin
->max_width
;
591 TM
->tmWeight
= pWin
->weight
;
593 TM
->tmDigitizedAspectX
= pWin
->horizontal_resolution
;
594 TM
->tmDigitizedAspectY
= pWin
->vertical_resolution
;
595 TM
->tmFirstChar
= pWin
->first_char
;
596 TM
->tmLastChar
= pWin
->last_char
;
597 TM
->tmDefaultChar
= pWin
->default_char
+ pWin
->first_char
;
598 TM
->tmBreakChar
= pWin
->break_char
+ pWin
->first_char
;
599 TM
->tmItalic
= pWin
->italic
;
600 TM
->tmUnderlined
= FontGDI
->Underline
;
601 TM
->tmStruckOut
= FontGDI
->StrikeOut
;
602 TM
->tmPitchAndFamily
= pWin
->pitch_and_family
;
603 TM
->tmCharSet
= pWin
->charset
;
607 if (pOS2
->usWinAscent
+ pOS2
->usWinDescent
== 0)
609 Ascent
= pHori
->Ascender
;
610 Descent
= -pHori
->Descender
;
614 Ascent
= pOS2
->usWinAscent
;
615 Descent
= pOS2
->usWinDescent
;
618 #if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */
619 TM
->tmAscent
= (FT_MulFix(Ascent
, YScale
) + 32) >> 6;
620 TM
->tmDescent
= (FT_MulFix(Descent
, YScale
) + 32) >> 6;
621 #else /* This (ros) code was previously affected by a FreeType bug, but it works now */
622 TM
->tmAscent
= (Face
->size
->metrics
.ascender
+ 32) >> 6; /* Units above baseline */
623 TM
->tmDescent
= (32 - Face
->size
->metrics
.descender
) >> 6; /* Units below baseline */
625 TM
->tmInternalLeading
= (FT_MulFix(Ascent
+ Descent
- Face
->units_per_EM
, YScale
) + 32) >> 6;
627 TM
->tmHeight
= TM
->tmAscent
+ TM
->tmDescent
;
630 * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
632 TM
->tmExternalLeading
= max(0, (FT_MulFix(pHori
->Line_Gap
633 - ((Ascent
+ Descent
)
634 - (pHori
->Ascender
- pHori
->Descender
)),
637 TM
->tmAveCharWidth
= (FT_MulFix(pOS2
->xAvgCharWidth
, XScale
) + 32) >> 6;
638 if (TM
->tmAveCharWidth
== 0)
640 TM
->tmAveCharWidth
= 1;
643 /* Correct forumla to get the maxcharwidth from unicode and ansi font */
644 TM
->tmMaxCharWidth
= (FT_MulFix(Face
->max_advance_width
, XScale
) + 32) >> 6;
646 TM
->tmWeight
= pOS2
->usWeightClass
;
648 TM
->tmDigitizedAspectX
= 96;
649 TM
->tmDigitizedAspectY
= 96;
650 if (face_has_symbol_charmap(Face
) || (pOS2
->usFirstCharIndex
>= 0xf000 && pOS2
->usFirstCharIndex
< 0xf100))
652 USHORT cpOEM
, cpAnsi
;
654 EngGetCurrentCodePage(&cpOEM
, &cpAnsi
);
658 case 1257: /* Baltic */
659 TM
->tmLastChar
= 0xf8fd;
662 TM
->tmLastChar
= 0xf0ff;
664 TM
->tmBreakChar
= 0x20;
665 TM
->tmDefaultChar
= 0x1f;
669 TM
->tmFirstChar
= pOS2
->usFirstCharIndex
; /* Should be the first char in the cmap */
670 TM
->tmLastChar
= pOS2
->usLastCharIndex
; /* Should be min(cmap_last, os2_last) */
672 if(pOS2
->usFirstCharIndex
<= 1)
673 TM
->tmBreakChar
= pOS2
->usFirstCharIndex
+ 2;
674 else if (pOS2
->usFirstCharIndex
> 0xff)
675 TM
->tmBreakChar
= 0x20;
677 TM
->tmBreakChar
= pOS2
->usFirstCharIndex
;
678 TM
->tmDefaultChar
= TM
->tmBreakChar
- 1;
680 TM
->tmItalic
= (Face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 255 : 0;
681 TM
->tmUnderlined
= FontGDI
->Underline
;
682 TM
->tmStruckOut
= FontGDI
->StrikeOut
;
684 /* Yes TPMF_FIXED_PITCH is correct; braindead api */
685 if (! FT_IS_FIXED_WIDTH(Face
))
687 TM
->tmPitchAndFamily
= TMPF_FIXED_PITCH
;
691 TM
->tmPitchAndFamily
= 0;
694 switch (pOS2
->panose
[PAN_FAMILYTYPE_INDEX
])
696 case PAN_FAMILY_SCRIPT
:
697 TM
->tmPitchAndFamily
|= FF_SCRIPT
;
699 case PAN_FAMILY_DECORATIVE
:
700 TM
->tmPitchAndFamily
|= FF_DECORATIVE
;
705 case PAN_FAMILY_TEXT_DISPLAY
:
706 case PAN_FAMILY_PICTORIAL
: /* Symbol fonts get treated as if they were text */
707 /* Which is clearly not what the panose spec says. */
708 if (TM
->tmPitchAndFamily
== 0) /* Fixed */
710 TM
->tmPitchAndFamily
= FF_MODERN
;
714 switch (pOS2
->panose
[PAN_SERIFSTYLE_INDEX
])
719 TM
->tmPitchAndFamily
|= FF_DONTCARE
;
723 case PAN_SERIF_OBTUSE_COVE
:
724 case PAN_SERIF_SQUARE_COVE
:
725 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
726 case PAN_SERIF_SQUARE
:
729 case PAN_SERIF_EXAGGERATED
:
730 case PAN_SERIF_TRIANGLE
:
731 TM
->tmPitchAndFamily
|= FF_ROMAN
;
734 case PAN_SERIF_NORMAL_SANS
:
735 case PAN_SERIF_OBTUSE_SANS
:
736 case PAN_SERIF_PERP_SANS
:
737 case PAN_SERIF_FLARED
:
738 case PAN_SERIF_ROUNDED
:
739 TM
->tmPitchAndFamily
|= FF_SWISS
;
745 TM
->tmPitchAndFamily
|= FF_DONTCARE
;
748 if (FT_IS_SCALABLE(Face
))
750 TM
->tmPitchAndFamily
|= TMPF_VECTOR
;
752 if (FT_IS_SFNT(Face
))
754 TM
->tmPitchAndFamily
|= TMPF_TRUETYPE
;
757 TM
->tmCharSet
= DEFAULT_CHARSET
;
760 /*************************************************************
761 * IntGetOutlineTextMetrics
765 IntGetOutlineTextMetrics(PFONTGDI FontGDI
,
767 OUTLINETEXTMETRICW
*Otm
)
771 TT_HoriHeader
*pHori
;
772 TT_Postscript
*pPost
;
773 FT_Fixed XScale
, YScale
;
774 ANSI_STRING FamilyNameA
, StyleNameA
;
775 UNICODE_STRING FamilyNameW
, StyleNameW
, Regular
;
776 FT_WinFNT_HeaderRec Win
;
780 Needed
= sizeof(OUTLINETEXTMETRICW
);
782 RtlInitAnsiString(&FamilyNameA
, FontGDI
->face
->family_name
);
783 RtlAnsiStringToUnicodeString(&FamilyNameW
, &FamilyNameA
, TRUE
);
785 RtlInitAnsiString(&StyleNameA
, FontGDI
->face
->style_name
);
786 RtlAnsiStringToUnicodeString(&StyleNameW
, &StyleNameA
, TRUE
);
788 /* These names should be read from the TT name table */
790 /* Length of otmpFamilyName */
791 Needed
+= FamilyNameW
.Length
+ sizeof(WCHAR
);
793 RtlInitUnicodeString(&Regular
, L
"regular");
794 /* Length of otmpFaceName */
795 if (0 == RtlCompareUnicodeString(&StyleNameW
, &Regular
, TRUE
))
797 Needed
+= FamilyNameW
.Length
+ sizeof(WCHAR
); /* Just the family name */
801 Needed
+= FamilyNameW
.Length
+ StyleNameW
.Length
+ (sizeof(WCHAR
) << 1); /* family + " " + style */
804 /* Length of otmpStyleName */
805 Needed
+= StyleNameW
.Length
+ sizeof(WCHAR
);
807 /* Length of otmpFullName */
808 Needed
+= FamilyNameW
.Length
+ StyleNameW
.Length
+ (sizeof(WCHAR
) << 1);
812 RtlFreeUnicodeString(&FamilyNameW
);
813 RtlFreeUnicodeString(&StyleNameW
);
817 XScale
= FontGDI
->face
->size
->metrics
.x_scale
;
818 YScale
= FontGDI
->face
->size
->metrics
.y_scale
;
821 pOS2
= FT_Get_Sfnt_Table(FontGDI
->face
, ft_sfnt_os2
);
825 DPRINT1("Can't find OS/2 table - not TT font?\n");
826 RtlFreeUnicodeString(&StyleNameW
);
827 RtlFreeUnicodeString(&FamilyNameW
);
831 pHori
= FT_Get_Sfnt_Table(FontGDI
->face
, ft_sfnt_hhea
);
835 DPRINT1("Can't find HHEA table - not TT font?\n");
836 RtlFreeUnicodeString(&StyleNameW
);
837 RtlFreeUnicodeString(&FamilyNameW
);
841 pPost
= FT_Get_Sfnt_Table(FontGDI
->face
, ft_sfnt_post
); /* We can live with this failing */
843 Error
= FT_Get_WinFNT_Header(FontGDI
->face
, &Win
);
845 Otm
->otmSize
= Needed
;
847 FillTM(&Otm
->otmTextMetrics
, FontGDI
, pOS2
, pHori
, !Error
? &Win
: 0);
850 RtlCopyMemory(&Otm
->otmPanoseNumber
, pOS2
->panose
, PANOSE_COUNT
);
851 Otm
->otmfsSelection
= pOS2
->fsSelection
;
852 Otm
->otmfsType
= pOS2
->fsType
;
853 Otm
->otmsCharSlopeRise
= pHori
->caret_Slope_Rise
;
854 Otm
->otmsCharSlopeRun
= pHori
->caret_Slope_Run
;
855 Otm
->otmItalicAngle
= 0; /* POST table */
856 Otm
->otmEMSquare
= FontGDI
->face
->units_per_EM
;
857 Otm
->otmAscent
= (FT_MulFix(pOS2
->sTypoAscender
, YScale
) + 32) >> 6;
858 Otm
->otmDescent
= (FT_MulFix(pOS2
->sTypoDescender
, YScale
) + 32) >> 6;
859 Otm
->otmLineGap
= (FT_MulFix(pOS2
->sTypoLineGap
, YScale
) + 32) >> 6;
860 Otm
->otmsCapEmHeight
= (FT_MulFix(pOS2
->sCapHeight
, YScale
) + 32) >> 6;
861 Otm
->otmsXHeight
= (FT_MulFix(pOS2
->sxHeight
, YScale
) + 32) >> 6;
862 Otm
->otmrcFontBox
.left
= (FT_MulFix(FontGDI
->face
->bbox
.xMin
, XScale
) + 32) >> 6;
863 Otm
->otmrcFontBox
.right
= (FT_MulFix(FontGDI
->face
->bbox
.xMax
, XScale
) + 32) >> 6;
864 Otm
->otmrcFontBox
.top
= (FT_MulFix(FontGDI
->face
->bbox
.yMax
, YScale
) + 32) >> 6;
865 Otm
->otmrcFontBox
.bottom
= (FT_MulFix(FontGDI
->face
->bbox
.yMin
, YScale
) + 32) >> 6;
866 Otm
->otmMacAscent
= Otm
->otmTextMetrics
.tmAscent
;
867 Otm
->otmMacDescent
= -Otm
->otmTextMetrics
.tmDescent
;
868 Otm
->otmMacLineGap
= Otm
->otmLineGap
;
869 Otm
->otmusMinimumPPEM
= 0; /* TT Header */
870 Otm
->otmptSubscriptSize
.x
= (FT_MulFix(pOS2
->ySubscriptXSize
, XScale
) + 32) >> 6;
871 Otm
->otmptSubscriptSize
.y
= (FT_MulFix(pOS2
->ySubscriptYSize
, YScale
) + 32) >> 6;
872 Otm
->otmptSubscriptOffset
.x
= (FT_MulFix(pOS2
->ySubscriptXOffset
, XScale
) + 32) >> 6;
873 Otm
->otmptSubscriptOffset
.y
= (FT_MulFix(pOS2
->ySubscriptYOffset
, YScale
) + 32) >> 6;
874 Otm
->otmptSuperscriptSize
.x
= (FT_MulFix(pOS2
->ySuperscriptXSize
, XScale
) + 32) >> 6;
875 Otm
->otmptSuperscriptSize
.y
= (FT_MulFix(pOS2
->ySuperscriptYSize
, YScale
) + 32) >> 6;
876 Otm
->otmptSuperscriptOffset
.x
= (FT_MulFix(pOS2
->ySuperscriptXOffset
, XScale
) + 32) >> 6;
877 Otm
->otmptSuperscriptOffset
.y
= (FT_MulFix(pOS2
->ySuperscriptYOffset
, YScale
) + 32) >> 6;
878 Otm
->otmsStrikeoutSize
= (FT_MulFix(pOS2
->yStrikeoutSize
, YScale
) + 32) >> 6;
879 Otm
->otmsStrikeoutPosition
= (FT_MulFix(pOS2
->yStrikeoutPosition
, YScale
) + 32) >> 6;
882 Otm
->otmsUnderscoreSize
= 0;
883 Otm
->otmsUnderscorePosition
= 0;
887 Otm
->otmsUnderscoreSize
= (FT_MulFix(pPost
->underlineThickness
, YScale
) + 32) >> 6;
888 Otm
->otmsUnderscorePosition
= (FT_MulFix(pPost
->underlinePosition
, YScale
) + 32) >> 6;
893 /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
894 Cp
= (char*) Otm
+ sizeof(OUTLINETEXTMETRICW
);
895 Otm
->otmpFamilyName
= (LPSTR
)(Cp
- (char*) Otm
);
896 wcscpy((WCHAR
*) Cp
, FamilyNameW
.Buffer
);
897 Cp
+= FamilyNameW
.Length
+ sizeof(WCHAR
);
898 Otm
->otmpStyleName
= (LPSTR
)(Cp
- (char*) Otm
);
899 wcscpy((WCHAR
*) Cp
, StyleNameW
.Buffer
);
900 Cp
+= StyleNameW
.Length
+ sizeof(WCHAR
);
901 Otm
->otmpFaceName
= (LPSTR
)(Cp
- (char*) Otm
);
902 wcscpy((WCHAR
*) Cp
, FamilyNameW
.Buffer
);
903 if (0 != RtlCompareUnicodeString(&StyleNameW
, &Regular
, TRUE
))
905 wcscat((WCHAR
*) Cp
, L
" ");
906 wcscat((WCHAR
*) Cp
, StyleNameW
.Buffer
);
907 Cp
+= FamilyNameW
.Length
+ StyleNameW
.Length
+ (sizeof(WCHAR
) << 1);
911 Cp
+= FamilyNameW
.Length
+ sizeof(WCHAR
);
913 Otm
->otmpFullName
= (LPSTR
)(Cp
- (char*) Otm
);
914 wcscpy((WCHAR
*) Cp
, FamilyNameW
.Buffer
);
915 wcscat((WCHAR
*) Cp
, L
" ");
916 wcscat((WCHAR
*) Cp
, StyleNameW
.Buffer
);
918 RtlFreeUnicodeString(&StyleNameW
);
919 RtlFreeUnicodeString(&FamilyNameW
);
924 static PFONTGDI FASTCALL
925 FindFaceNameInList(PUNICODE_STRING FaceName
, PLIST_ENTRY Head
)
928 PFONT_ENTRY CurrentEntry
;
929 ANSI_STRING EntryFaceNameA
;
930 UNICODE_STRING EntryFaceNameW
;
934 while (Entry
!= Head
)
936 CurrentEntry
= (PFONT_ENTRY
) CONTAINING_RECORD(Entry
, FONT_ENTRY
, ListEntry
);
938 FontGDI
= CurrentEntry
->Font
;
941 RtlInitAnsiString(&EntryFaceNameA
, FontGDI
->face
->family_name
);
942 RtlAnsiStringToUnicodeString(&EntryFaceNameW
, &EntryFaceNameA
, TRUE
);
943 if ((LF_FACESIZE
- 1) * sizeof(WCHAR
) < EntryFaceNameW
.Length
)
945 EntryFaceNameW
.Length
= (LF_FACESIZE
- 1) * sizeof(WCHAR
);
946 EntryFaceNameW
.Buffer
[LF_FACESIZE
- 1] = L
'\0';
949 if (0 == RtlCompareUnicodeString(FaceName
, &EntryFaceNameW
, TRUE
))
951 RtlFreeUnicodeString(&EntryFaceNameW
);
955 RtlFreeUnicodeString(&EntryFaceNameW
);
956 Entry
= Entry
->Flink
;
962 static PFONTGDI FASTCALL
963 FindFaceNameInLists(PUNICODE_STRING FaceName
)
965 PPROCESSINFO Win32Process
;
968 /* Search the process local list */
969 Win32Process
= PsGetCurrentProcessWin32Process();
970 IntLockProcessPrivateFonts(Win32Process
);
971 Font
= FindFaceNameInList(FaceName
, &Win32Process
->PrivateFontListHead
);
972 IntUnLockProcessPrivateFonts(Win32Process
);
978 /* Search the global list */
980 Font
= FindFaceNameInList(FaceName
, &FontListHead
);
981 IntUnLockGlobalFonts
;
987 FontFamilyFillInfo(PFONTFAMILYINFO Info
, PCWSTR FaceName
, PFONTGDI FontGDI
)
990 UNICODE_STRING StyleW
;
993 CHARSETINFO CharSetInfo
;
995 OUTLINETEXTMETRICW
*Otm
;
1001 RtlZeroMemory(Info
, sizeof(FONTFAMILYINFO
));
1002 Size
= IntGetOutlineTextMetrics(FontGDI
, 0, NULL
);
1003 Otm
= ExAllocatePoolWithTag(PagedPool
, Size
, GDITAG_TEXT
);
1008 IntGetOutlineTextMetrics(FontGDI
, Size
, Otm
);
1010 Lf
= &Info
->EnumLogFontEx
.elfLogFont
;
1011 TM
= &Otm
->otmTextMetrics
;
1013 Lf
->lfHeight
= TM
->tmHeight
;
1014 Lf
->lfWidth
= TM
->tmAveCharWidth
;
1015 Lf
->lfWeight
= TM
->tmWeight
;
1016 Lf
->lfItalic
= TM
->tmItalic
;
1017 Lf
->lfPitchAndFamily
= (TM
->tmPitchAndFamily
& 0xf1) + 1;
1018 Lf
->lfCharSet
= TM
->tmCharSet
;
1019 Lf
->lfOutPrecision
= OUT_OUTLINE_PRECIS
;
1020 Lf
->lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1021 Lf
->lfQuality
= PROOF_QUALITY
;
1023 Ntm
= &Info
->NewTextMetricEx
.ntmTm
;
1024 Ntm
->tmHeight
= TM
->tmHeight
;
1025 Ntm
->tmAscent
= TM
->tmAscent
;
1026 Ntm
->tmDescent
= TM
->tmDescent
;
1027 Ntm
->tmInternalLeading
= TM
->tmInternalLeading
;
1028 Ntm
->tmExternalLeading
= TM
->tmExternalLeading
;
1029 Ntm
->tmAveCharWidth
= TM
->tmAveCharWidth
;
1030 Ntm
->tmMaxCharWidth
= TM
->tmMaxCharWidth
;
1031 Ntm
->tmWeight
= TM
->tmWeight
;
1032 Ntm
->tmOverhang
= TM
->tmOverhang
;
1033 Ntm
->tmDigitizedAspectX
= TM
->tmDigitizedAspectX
;
1034 Ntm
->tmDigitizedAspectY
= TM
->tmDigitizedAspectY
;
1035 Ntm
->tmFirstChar
= TM
->tmFirstChar
;
1036 Ntm
->tmLastChar
= TM
->tmLastChar
;
1037 Ntm
->tmDefaultChar
= TM
->tmDefaultChar
;
1038 Ntm
->tmBreakChar
= TM
->tmBreakChar
;
1039 Ntm
->tmItalic
= TM
->tmItalic
;
1040 Ntm
->tmUnderlined
= TM
->tmUnderlined
;
1041 Ntm
->tmStruckOut
= TM
->tmStruckOut
;
1042 Ntm
->tmPitchAndFamily
= TM
->tmPitchAndFamily
;
1043 Ntm
->tmCharSet
= TM
->tmCharSet
;
1044 Ntm
->ntmFlags
= TM
->tmItalic
? NTM_ITALIC
: 0;
1046 if (550 < TM
->tmWeight
) Ntm
->ntmFlags
|= NTM_BOLD
;
1048 if (0 == Ntm
->ntmFlags
) Ntm
->ntmFlags
= NTM_REGULAR
;
1050 Ntm
->ntmSizeEM
= Otm
->otmEMSquare
;
1051 Ntm
->ntmCellHeight
= 0;
1052 Ntm
->ntmAvgWidth
= 0;
1054 Info
->FontType
= (0 != (TM
->tmPitchAndFamily
& TMPF_TRUETYPE
)
1055 ? TRUETYPE_FONTTYPE
: 0);
1057 if (0 == (TM
->tmPitchAndFamily
& TMPF_VECTOR
))
1058 Info
->FontType
|= RASTER_FONTTYPE
;
1060 ExFreePoolWithTag(Otm
, GDITAG_TEXT
);
1062 RtlStringCbCopyW(Info
->EnumLogFontEx
.elfLogFont
.lfFaceName
,
1063 sizeof(Info
->EnumLogFontEx
.elfLogFont
.lfFaceName
),
1065 RtlStringCbCopyW(Info
->EnumLogFontEx
.elfFullName
,
1066 sizeof(Info
->EnumLogFontEx
.elfFullName
),
1068 RtlInitAnsiString(&StyleA
, FontGDI
->face
->style_name
);
1069 StyleW
.Buffer
= Info
->EnumLogFontEx
.elfStyle
;
1070 StyleW
.MaximumLength
= sizeof(Info
->EnumLogFontEx
.elfStyle
);
1071 RtlAnsiStringToUnicodeString(&StyleW
, &StyleA
, FALSE
);
1073 Info
->EnumLogFontEx
.elfLogFont
.lfCharSet
= DEFAULT_CHARSET
;
1074 Info
->EnumLogFontEx
.elfScript
[0] = L
'\0';
1076 pOS2
= FT_Get_Sfnt_Table(FontGDI
->face
, ft_sfnt_os2
);
1080 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
1081 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
1082 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
1083 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
1084 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
1085 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
1087 if (0 == pOS2
->version
)
1091 if (FT_Get_First_Char(FontGDI
->face
, &Dummy
) < 0x100)
1092 fs
.fsCsb
[0] |= FS_LATIN1
;
1094 fs
.fsCsb
[0] |= FS_SYMBOL
;
1096 if (fs
.fsCsb
[0] == 0)
1097 { /* Let's see if we can find any interesting cmaps */
1098 for (i
= 0; i
< FontGDI
->face
->num_charmaps
; i
++)
1100 switch (FontGDI
->face
->charmaps
[i
]->encoding
)
1102 case FT_ENCODING_UNICODE
:
1103 case FT_ENCODING_APPLE_ROMAN
:
1104 fs
.fsCsb
[0] |= FS_LATIN1
;
1106 case FT_ENCODING_MS_SYMBOL
:
1107 fs
.fsCsb
[0] |= FS_SYMBOL
;
1114 for (i
= 0; i
< MAXTCIINDEX
; i
++)
1117 if (fs
.fsCsb
[0] & fs0
)
1119 if (!IntTranslateCharsetInfo(&fs0
, &CharSetInfo
, TCI_SRCFONTSIG
))
1121 CharSetInfo
.ciCharset
= DEFAULT_CHARSET
;
1123 if (DEFAULT_CHARSET
!= CharSetInfo
.ciCharset
)
1125 Info
->EnumLogFontEx
.elfLogFont
.lfCharSet
= CharSetInfo
.ciCharset
;
1126 if (NULL
!= ElfScripts
[i
])
1127 wcscpy(Info
->EnumLogFontEx
.elfScript
, ElfScripts
[i
]);
1130 DPRINT1("Unknown elfscript for bit %u\n", i
);
1135 Info
->NewTextMetricEx
.ntmFontSig
= fs
;
1140 FindFaceNameInInfo(PUNICODE_STRING FaceName
, PFONTFAMILYINFO Info
, DWORD InfoEntries
)
1143 UNICODE_STRING InfoFaceName
;
1145 for (i
= 0; i
< InfoEntries
; i
++)
1147 RtlInitUnicodeString(&InfoFaceName
, Info
[i
].EnumLogFontEx
.elfLogFont
.lfFaceName
);
1148 if (0 == RtlCompareUnicodeString(&InfoFaceName
, FaceName
, TRUE
))
1157 static BOOLEAN FASTCALL
1158 FontFamilyInclude(LPLOGFONTW LogFont
, PUNICODE_STRING FaceName
,
1159 PFONTFAMILYINFO Info
, DWORD InfoEntries
)
1161 UNICODE_STRING LogFontFaceName
;
1163 RtlInitUnicodeString(&LogFontFaceName
, LogFont
->lfFaceName
);
1164 if (0 != LogFontFaceName
.Length
1165 && 0 != RtlCompareUnicodeString(&LogFontFaceName
, FaceName
, TRUE
))
1170 return FindFaceNameInInfo(FaceName
, Info
, InfoEntries
) < 0;
1173 static BOOLEAN FASTCALL
1174 GetFontFamilyInfoForList(LPLOGFONTW LogFont
,
1175 PFONTFAMILYINFO Info
,
1181 PFONT_ENTRY CurrentEntry
;
1182 ANSI_STRING EntryFaceNameA
;
1183 UNICODE_STRING EntryFaceNameW
;
1186 Entry
= Head
->Flink
;
1187 while (Entry
!= Head
)
1189 CurrentEntry
= (PFONT_ENTRY
) CONTAINING_RECORD(Entry
, FONT_ENTRY
, ListEntry
);
1191 FontGDI
= CurrentEntry
->Font
;
1194 RtlInitAnsiString(&EntryFaceNameA
, FontGDI
->face
->family_name
);
1195 RtlAnsiStringToUnicodeString(&EntryFaceNameW
, &EntryFaceNameA
, TRUE
);
1196 if ((LF_FACESIZE
- 1) * sizeof(WCHAR
) < EntryFaceNameW
.Length
)
1198 EntryFaceNameW
.Length
= (LF_FACESIZE
- 1) * sizeof(WCHAR
);
1199 EntryFaceNameW
.Buffer
[LF_FACESIZE
- 1] = L
'\0';
1202 if (FontFamilyInclude(LogFont
, &EntryFaceNameW
, Info
, min(*Count
, Size
)))
1206 FontFamilyFillInfo(Info
+ *Count
, EntryFaceNameW
.Buffer
, FontGDI
);
1210 RtlFreeUnicodeString(&EntryFaceNameW
);
1211 Entry
= Entry
->Flink
;
1217 typedef struct FontFamilyInfoCallbackContext
1220 PFONTFAMILYINFO Info
;
1223 } FONT_FAMILY_INFO_CALLBACK_CONTEXT
, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT
;
1225 static NTSTATUS APIENTRY
1226 FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName
, IN ULONG ValueType
,
1227 IN PVOID ValueData
, IN ULONG ValueLength
,
1228 IN PVOID Context
, IN PVOID EntryContext
)
1230 PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext
;
1231 UNICODE_STRING RegistryName
, RegistryValue
;
1235 if (REG_SZ
!= ValueType
)
1237 return STATUS_SUCCESS
;
1239 InfoContext
= (PFONT_FAMILY_INFO_CALLBACK_CONTEXT
) Context
;
1240 RtlInitUnicodeString(&RegistryName
, ValueName
);
1242 /* Do we need to include this font family? */
1243 if (FontFamilyInclude(InfoContext
->LogFont
, &RegistryName
, InfoContext
->Info
,
1244 min(InfoContext
->Count
, InfoContext
->Size
)))
1246 RtlInitUnicodeString(&RegistryValue
, (PCWSTR
) ValueData
);
1247 Existing
= FindFaceNameInInfo(&RegistryValue
, InfoContext
->Info
,
1248 min(InfoContext
->Count
, InfoContext
->Size
));
1251 /* We already have the information about the "real" font. Just copy it */
1252 if (InfoContext
->Count
< InfoContext
->Size
)
1254 InfoContext
->Info
[InfoContext
->Count
] = InfoContext
->Info
[Existing
];
1255 RtlStringCbCopyNW(InfoContext
->Info
[InfoContext
->Count
].EnumLogFontEx
.elfLogFont
.lfFaceName
,
1256 sizeof(InfoContext
->Info
[InfoContext
->Count
].EnumLogFontEx
.elfLogFont
.lfFaceName
),
1257 RegistryName
.Buffer
,
1258 RegistryName
.Length
);
1260 InfoContext
->Count
++;
1261 return STATUS_SUCCESS
;
1264 /* Try to find information about the "real" font */
1265 FontGDI
= FindFaceNameInLists(&RegistryValue
);
1266 if (NULL
== FontGDI
)
1268 /* "Real" font not found, discard this registry entry */
1269 return STATUS_SUCCESS
;
1272 /* Return info about the "real" font but with the name of the alias */
1273 if (InfoContext
->Count
< InfoContext
->Size
)
1275 FontFamilyFillInfo(InfoContext
->Info
+ InfoContext
->Count
,
1276 RegistryName
.Buffer
, FontGDI
);
1278 InfoContext
->Count
++;
1279 return STATUS_SUCCESS
;
1282 return STATUS_SUCCESS
;
1285 static BOOLEAN FASTCALL
1286 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont
,
1287 PFONTFAMILYINFO Info
,
1291 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = {{0}};
1292 FONT_FAMILY_INFO_CALLBACK_CONTEXT Context
;
1295 /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
1296 The real work is done in the registry callback function */
1297 Context
.LogFont
= LogFont
;
1298 Context
.Info
= Info
;
1299 Context
.Count
= *Count
;
1300 Context
.Size
= Size
;
1302 QueryTable
[0].QueryRoutine
= FontFamilyInfoQueryRegistryCallback
;
1303 QueryTable
[0].Flags
= 0;
1304 QueryTable
[0].Name
= NULL
;
1305 QueryTable
[0].EntryContext
= NULL
;
1306 QueryTable
[0].DefaultType
= REG_NONE
;
1307 QueryTable
[0].DefaultData
= NULL
;
1308 QueryTable
[0].DefaultLength
= 0;
1310 QueryTable
[1].QueryRoutine
= NULL
;
1311 QueryTable
[1].Name
= NULL
;
1313 Status
= RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT
,
1318 if (NT_SUCCESS(Status
))
1320 *Count
= Context
.Count
;
1323 return NT_SUCCESS(Status
) || STATUS_OBJECT_NAME_NOT_FOUND
== Status
;
1328 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs
)
1332 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
1333 lprs
->wFlags
= TT_AVAILABLE
| TT_ENABLED
;
1334 lprs
->nLanguageID
= gusLanguageID
;
1337 EngSetLastError(ERROR_INVALID_PARAMETER
);
1347 return (FLOATOBJ_Equal(&pmx1
->efM11
, &pmx2
->efM11
) &&
1348 FLOATOBJ_Equal(&pmx1
->efM12
, &pmx2
->efM12
) &&
1349 FLOATOBJ_Equal(&pmx1
->efM21
, &pmx2
->efM21
) &&
1350 FLOATOBJ_Equal(&pmx1
->efM22
, &pmx2
->efM22
));
1353 FT_BitmapGlyph APIENTRY
1360 PLIST_ENTRY CurrentEntry
;
1361 PFONT_CACHE_ENTRY FontEntry
;
1363 CurrentEntry
= FontCacheListHead
.Flink
;
1364 while (CurrentEntry
!= &FontCacheListHead
)
1366 FontEntry
= (PFONT_CACHE_ENTRY
)CurrentEntry
;
1367 if ((FontEntry
->Face
== Face
) &&
1368 (FontEntry
->GlyphIndex
== GlyphIndex
) &&
1369 (FontEntry
->Height
== Height
) &&
1370 (SameScaleMatrix(&FontEntry
->mxWorldToDevice
, pmx
)))
1372 CurrentEntry
= CurrentEntry
->Flink
;
1375 if (CurrentEntry
== &FontCacheListHead
)
1380 RemoveEntryList(CurrentEntry
);
1381 InsertHeadList(&FontCacheListHead
, CurrentEntry
);
1382 return FontEntry
->BitmapGlyph
;
1385 FT_BitmapGlyph APIENTRY
1391 FT_GlyphSlot GlyphSlot
,
1392 FT_Render_Mode RenderMode
)
1396 PFONT_CACHE_ENTRY NewEntry
;
1397 FT_Bitmap AlignedBitmap
;
1398 FT_BitmapGlyph BitmapGlyph
;
1400 error
= FT_Get_Glyph(GlyphSlot
, &GlyphCopy
);
1403 DPRINT1("Failure caching glyph.\n");
1407 error
= FT_Glyph_To_Bitmap(&GlyphCopy
, RenderMode
, 0, 1);
1410 FT_Done_Glyph(GlyphCopy
);
1411 DPRINT1("Failure rendering glyph.\n");
1415 NewEntry
= ExAllocatePoolWithTag(PagedPool
, sizeof(FONT_CACHE_ENTRY
), TAG_FONT
);
1418 DPRINT1("Alloc failure caching glyph.\n");
1419 FT_Done_Glyph(GlyphCopy
);
1423 BitmapGlyph
= (FT_BitmapGlyph
)GlyphCopy
;
1424 FT_Bitmap_New(&AlignedBitmap
);
1425 if(FT_Bitmap_Convert(GlyphSlot
->library
, &BitmapGlyph
->bitmap
, &AlignedBitmap
, 4))
1427 DPRINT1("Conversion failed\n");
1428 ExFreePoolWithTag(NewEntry
, TAG_FONT
);
1429 FT_Done_Glyph((FT_Glyph
)BitmapGlyph
);
1433 FT_Bitmap_Done(GlyphSlot
->library
, &BitmapGlyph
->bitmap
);
1434 BitmapGlyph
->bitmap
= AlignedBitmap
;
1436 NewEntry
->GlyphIndex
= GlyphIndex
;
1437 NewEntry
->Face
= Face
;
1438 NewEntry
->BitmapGlyph
= BitmapGlyph
;
1439 NewEntry
->Height
= Height
;
1440 NewEntry
->mxWorldToDevice
= *pmx
;
1442 InsertHeadList(&FontCacheListHead
, &NewEntry
->ListEntry
);
1443 if (FontCacheNumEntries
++ > MAX_FONT_CACHE
)
1445 NewEntry
= (PFONT_CACHE_ENTRY
)FontCacheListHead
.Blink
;
1446 FT_Done_Glyph((FT_Glyph
)NewEntry
->BitmapGlyph
);
1447 RemoveTailList(&FontCacheListHead
);
1448 ExFreePoolWithTag(NewEntry
, TAG_FONT
);
1449 FontCacheNumEntries
--;
1458 FTVectorToPOINTFX(FT_Vector
*vec
, POINTFX
*pt
)
1460 pt
->x
.value
= vec
->x
>> 6;
1461 pt
->x
.fract
= (vec
->x
& 0x3f) << 10;
1462 pt
->x
.fract
|= ((pt
->x
.fract
>> 6) | (pt
->x
.fract
>> 12));
1463 pt
->y
.value
= vec
->y
>> 6;
1464 pt
->y
.fract
= (vec
->y
& 0x3f) << 10;
1465 pt
->y
.fract
|= ((pt
->y
.fract
>> 6) | (pt
->y
.fract
>> 12));
1470 This function builds an FT_Fixed from a float. It puts the integer part
1471 in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
1472 It fails if the integer part of the float number is greater than SHORT_MAX.
1474 static __inline FT_Fixed
FT_FixedFromFloat(float f
)
1477 unsigned short fract
= (f
- value
) * 0xFFFF;
1478 return (FT_Fixed
)((long)value
<< 16 | (unsigned long)fract
);
1482 This function builds an FT_Fixed from a FIXED. It simply put f.value
1483 in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
1485 static __inline FT_Fixed
FT_FixedFromFIXED(FIXED f
)
1487 return (FT_Fixed
)((long)f
.value
<< 16 | (unsigned long)f
.fract
);
1491 * Based on WineEngGetGlyphOutline
1496 ftGdiGetGlyphOutline(
1504 BOOL bIgnoreRotation
)
1506 static const FT_Matrix identityMat
= {(1 << 16), 0, 0, (1 << 16)};
1514 FT_UInt glyph_index
;
1515 DWORD width
, height
, pitch
, needed
= 0;
1516 FT_Bitmap ft_bitmap
;
1518 INT left
, right
, top
= 0, bottom
= 0;
1520 FT_Int load_flags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
;
1521 FLOAT eM11
, widthRatio
= 1.0;
1522 FT_Matrix transMat
= identityMat
;
1523 BOOL needsTransform
= FALSE
;
1526 INT adv
, lsb
, bbx
; /* These three hold to widths of the unrotated chars */
1527 OUTLINETEXTMETRICW
*potm
;
1529 FT_CharMap found
= 0, charmap
;
1532 DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch
, iFormat
, pgm
,
1533 cjBuf
, pvBuf
, pmat2
);
1535 pdcattr
= dc
->pdcattr
;
1537 MatrixS2XForm(&xForm
, &dc
->pdcattr
->mxWorldToDevice
);
1540 hFont
= pdcattr
->hlfntNew
;
1541 TextObj
= RealizeFontInit(hFont
);
1545 EngSetLastError(ERROR_INVALID_HANDLE
);
1548 FontGDI
= ObjToGDI(TextObj
->Font
, FONT
);
1549 ft_face
= FontGDI
->face
;
1551 aveWidth
= FT_IS_SCALABLE(ft_face
) ? TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfWidth
: 0;
1552 orientation
= FT_IS_SCALABLE(ft_face
) ? TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfOrientation
: 0;
1554 Size
= IntGetOutlineTextMetrics(FontGDI
, 0, NULL
);
1555 potm
= ExAllocatePoolWithTag(PagedPool
, Size
, GDITAG_TEXT
);
1558 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1559 TEXTOBJ_UnlockText(TextObj
);
1562 IntGetOutlineTextMetrics(FontGDI
, Size
, potm
);
1566 /* During testing, I never saw this used. It is here just in case. */
1567 if (ft_face
->charmap
== NULL
)
1569 DPRINT("WARNING: No charmap selected!\n");
1570 DPRINT("This font face has %d charmaps\n", ft_face
->num_charmaps
);
1572 for (n
= 0; n
< ft_face
->num_charmaps
; n
++)
1574 charmap
= ft_face
->charmaps
[n
];
1575 DPRINT("Found charmap encoding: %u\n", charmap
->encoding
);
1576 if (charmap
->encoding
!= 0)
1584 DPRINT1("WARNING: Could not find desired charmap!\n");
1586 error
= FT_Set_Charmap(ft_face
, found
);
1589 DPRINT1("WARNING: Could not set the charmap!\n");
1593 // FT_Set_Pixel_Sizes(ft_face,
1594 // TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
1595 /* FIXME: Should set character height if neg */
1596 // (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
1597 // dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
1598 // FtSetCoordinateTransform(face, DC_pmxWorldToDevice(dc));
1600 TEXTOBJ_UnlockText(TextObj
);
1602 if (iFormat
& GGO_GLYPH_INDEX
)
1605 iFormat
&= ~GGO_GLYPH_INDEX
;
1607 else glyph_index
= FT_Get_Char_Index(ft_face
, wch
);
1609 if (orientation
|| (iFormat
!= GGO_METRICS
&& iFormat
!= GGO_BITMAP
) || aveWidth
|| pmat2
)
1610 load_flags
|= FT_LOAD_NO_BITMAP
;
1612 if (iFormat
& GGO_UNHINTED
)
1614 load_flags
|= FT_LOAD_NO_HINTING
;
1615 iFormat
&= ~GGO_UNHINTED
;
1618 error
= FT_Load_Glyph(ft_face
, glyph_index
, load_flags
);
1621 DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index
);
1623 if (potm
) ExFreePoolWithTag(potm
, GDITAG_TEXT
);
1628 if (aveWidth
&& potm
)
1630 widthRatio
= (FLOAT
)aveWidth
* eM11
/
1631 (FLOAT
) potm
->otmTextMetrics
.tmAveCharWidth
;
1634 left
= (INT
)(ft_face
->glyph
->metrics
.horiBearingX
* widthRatio
) & -64;
1635 right
= (INT
)((ft_face
->glyph
->metrics
.horiBearingX
+
1636 ft_face
->glyph
->metrics
.width
) * widthRatio
+ 63) & -64;
1638 adv
= (INT
)((ft_face
->glyph
->metrics
.horiAdvance
* widthRatio
) + 63) >> 6;
1640 bbx
= (right
- left
) >> 6;
1642 DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv
, lsb
, bbx
);
1646 /* Scaling transform */
1653 PMATRIX pmx
= DC_pmxWorldToDevice(dc
);
1655 /* Create a freetype matrix, by converting to 16.16 fixpoint format */
1656 efTemp
= pmx
->efM11
;
1657 FLOATOBJ_MulLong(&efTemp
, 0x00010000);
1658 ftmatrix
.xx
= FLOATOBJ_GetLong(&efTemp
);
1660 efTemp
= pmx
->efM12
;
1661 FLOATOBJ_MulLong(&efTemp
, 0x00010000);
1662 ftmatrix
.xy
= FLOATOBJ_GetLong(&efTemp
);
1664 efTemp
= pmx
->efM21
;
1665 FLOATOBJ_MulLong(&efTemp
, 0x00010000);
1666 ftmatrix
.yx
= FLOATOBJ_GetLong(&efTemp
);
1668 efTemp
= pmx
->efM22
;
1669 FLOATOBJ_MulLong(&efTemp
, 0x00010000);
1670 ftmatrix
.yy
= FLOATOBJ_GetLong(&efTemp
);
1672 FT_Matrix_Multiply(&ftmatrix
, &transMat
);
1673 needsTransform
= TRUE
;
1676 /* Slant transform */
1677 if (potm
->otmTextMetrics
.tmItalic
)
1680 DPRINT("Slant Trans!\n");
1681 slantMat
.xx
= (1 << 16);
1682 slantMat
.xy
= ((1 << 16) >> 2);
1684 slantMat
.yy
= (1 << 16);
1685 FT_Matrix_Multiply(&slantMat
, &transMat
);
1686 needsTransform
= TRUE
;
1689 /* Rotation transform */
1692 FT_Matrix rotationMat
;
1694 DPRINT("Rotation Trans!\n");
1695 angle
= FT_FixedFromFloat((float)orientation
/ 10.0);
1696 FT_Vector_Unit(&vecAngle
, angle
);
1697 rotationMat
.xx
= vecAngle
.x
;
1698 rotationMat
.xy
= -vecAngle
.y
;
1699 rotationMat
.yx
= -rotationMat
.xy
;
1700 rotationMat
.yy
= rotationMat
.xx
;
1701 FT_Matrix_Multiply(&rotationMat
, &transMat
);
1702 needsTransform
= TRUE
;
1705 /* Extra transformation specified by caller */
1709 DPRINT("MAT2 Matrix Trans!\n");
1710 extraMat
.xx
= FT_FixedFromFIXED(pmat2
->eM11
);
1711 extraMat
.xy
= FT_FixedFromFIXED(pmat2
->eM21
);
1712 extraMat
.yx
= FT_FixedFromFIXED(pmat2
->eM12
);
1713 extraMat
.yy
= FT_FixedFromFIXED(pmat2
->eM22
);
1714 FT_Matrix_Multiply(&extraMat
, &transMat
);
1715 needsTransform
= TRUE
;
1718 if (potm
) ExFreePoolWithTag(potm
, GDITAG_TEXT
); /* It looks like we are finished with potm ATM. */
1720 if (!needsTransform
)
1722 DPRINT("No Need to be Transformed!\n");
1723 top
= (ft_face
->glyph
->metrics
.horiBearingY
+ 63) & -64;
1724 bottom
= (ft_face
->glyph
->metrics
.horiBearingY
-
1725 ft_face
->glyph
->metrics
.height
) & -64;
1726 gm
.gmCellIncX
= adv
;
1733 for (xc
= 0; xc
< 2; xc
++)
1735 for (yc
= 0; yc
< 2; yc
++)
1737 vec
.x
= (ft_face
->glyph
->metrics
.horiBearingX
+
1738 xc
* ft_face
->glyph
->metrics
.width
);
1739 vec
.y
= ft_face
->glyph
->metrics
.horiBearingY
-
1740 yc
* ft_face
->glyph
->metrics
.height
;
1741 DPRINT("Vec %ld,%ld\n", vec
.x
, vec
.y
);
1742 FT_Vector_Transform(&vec
, &transMat
);
1743 if (xc
== 0 && yc
== 0)
1745 left
= right
= vec
.x
;
1746 top
= bottom
= vec
.y
;
1750 if (vec
.x
< left
) left
= vec
.x
;
1751 else if (vec
.x
> right
) right
= vec
.x
;
1752 if (vec
.y
< bottom
) bottom
= vec
.y
;
1753 else if (vec
.y
> top
) top
= vec
.y
;
1758 right
= (right
+ 63) & -64;
1759 bottom
= bottom
& -64;
1760 top
= (top
+ 63) & -64;
1762 DPRINT("Transformed box: (%d,%d - %d,%d)\n", left
, top
, right
, bottom
);
1763 vec
.x
= ft_face
->glyph
->metrics
.horiAdvance
;
1765 FT_Vector_Transform(&vec
, &transMat
);
1766 gm
.gmCellIncX
= (vec
.x
+63) >> 6;
1767 gm
.gmCellIncY
= -((vec
.y
+63) >> 6);
1769 gm
.gmBlackBoxX
= (right
- left
) >> 6;
1770 gm
.gmBlackBoxY
= (top
- bottom
) >> 6;
1771 gm
.gmptGlyphOrigin
.x
= left
>> 6;
1772 gm
.gmptGlyphOrigin
.y
= top
>> 6;
1774 DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
1775 gm
.gmCellIncX
, gm
.gmCellIncY
,
1776 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
,
1777 gm
.gmptGlyphOrigin
.x
, gm
.gmptGlyphOrigin
.y
);
1781 if (pgm
) RtlCopyMemory(pgm
, &gm
, sizeof(GLYPHMETRICS
));
1783 if (iFormat
== GGO_METRICS
)
1785 DPRINT("GGO_METRICS Exit!\n");
1786 return 1; /* FIXME */
1789 if (ft_face
->glyph
->format
!= ft_glyph_format_outline
&& iFormat
!= GGO_BITMAP
)
1791 DPRINT1("Loaded a bitmap\n");
1798 width
= gm
.gmBlackBoxX
;
1799 height
= gm
.gmBlackBoxY
;
1800 pitch
= ((width
+ 31) >> 5) << 2;
1801 needed
= pitch
* height
;
1803 if (!pvBuf
|| !cjBuf
) break;
1805 switch (ft_face
->glyph
->format
)
1807 case ft_glyph_format_bitmap
:
1809 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= pvBuf
;
1810 INT w
= (ft_face
->glyph
->bitmap
.width
+ 7) >> 3;
1811 INT h
= ft_face
->glyph
->bitmap
.rows
;
1814 RtlCopyMemory(dst
, src
, w
);
1815 src
+= ft_face
->glyph
->bitmap
.pitch
;
1821 case ft_glyph_format_outline
:
1822 ft_bitmap
.width
= width
;
1823 ft_bitmap
.rows
= height
;
1824 ft_bitmap
.pitch
= pitch
;
1825 ft_bitmap
.pixel_mode
= ft_pixel_mode_mono
;
1826 ft_bitmap
.buffer
= pvBuf
;
1831 FT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
1833 FT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1834 /* Note: FreeType will only set 'black' bits for us. */
1835 RtlZeroMemory(pvBuf
, needed
);
1836 FT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1841 DPRINT1("Loaded glyph format %x\n", ft_face
->glyph
->format
);
1846 case GGO_GRAY2_BITMAP
:
1847 case GGO_GRAY4_BITMAP
:
1848 case GGO_GRAY8_BITMAP
:
1850 unsigned int mult
, row
, col
;
1853 width
= gm
.gmBlackBoxX
;
1854 height
= gm
.gmBlackBoxY
;
1855 pitch
= (width
+ 3) / 4 * 4;
1856 needed
= pitch
* height
;
1858 if (!pvBuf
|| !cjBuf
) break;
1860 switch (ft_face
->glyph
->format
)
1862 case ft_glyph_format_bitmap
:
1864 BYTE
*src
= ft_face
->glyph
->bitmap
.buffer
, *dst
= pvBuf
;
1865 INT h
= ft_face
->glyph
->bitmap
.rows
;
1869 for (x
= 0; x
< pitch
; x
++)
1871 if (x
< ft_face
->glyph
->bitmap
.width
)
1872 dst
[x
] = (src
[x
/ 8] & (1 << ( (7 - (x
% 8))))) ? 0xff : 0;
1876 src
+= ft_face
->glyph
->bitmap
.pitch
;
1881 case ft_glyph_format_outline
:
1883 ft_bitmap
.width
= width
;
1884 ft_bitmap
.rows
= height
;
1885 ft_bitmap
.pitch
= pitch
;
1886 ft_bitmap
.pixel_mode
= ft_pixel_mode_grays
;
1887 ft_bitmap
.buffer
= pvBuf
;
1892 FT_Outline_Transform(&ft_face
->glyph
->outline
, &transMat
);
1894 FT_Outline_Translate(&ft_face
->glyph
->outline
, -left
, -bottom
);
1895 RtlZeroMemory(ft_bitmap
.buffer
, cjBuf
);
1896 FT_Outline_Get_Bitmap(library
, &ft_face
->glyph
->outline
, &ft_bitmap
);
1899 if (iFormat
== GGO_GRAY2_BITMAP
)
1901 else if (iFormat
== GGO_GRAY4_BITMAP
)
1903 else if (iFormat
== GGO_GRAY8_BITMAP
)
1911 DPRINT1("Loaded glyph format %x\n", ft_face
->glyph
->format
);
1915 for (row
= 0; row
< height
; row
++)
1918 for (col
= 0; col
< width
; col
++, ptr
++)
1920 *ptr
= (((int)*ptr
) * mult
+ 128) / 256;
1929 int contour
, point
= 0, first_pt
;
1930 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
1931 TTPOLYGONHEADER
*pph
;
1933 DWORD pph_start
, cpfx
, type
;
1935 if (cjBuf
== 0) pvBuf
= NULL
; /* This is okay, need cjBuf to allocate. */
1938 if (needsTransform
&& pvBuf
) FT_Outline_Transform(outline
, &transMat
);
1940 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
1943 pph
= (TTPOLYGONHEADER
*)((char *)pvBuf
+ needed
);
1947 pph
->dwType
= TT_POLYGON_TYPE
;
1948 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
1950 needed
+= sizeof(*pph
);
1952 while (point
<= outline
->contours
[contour
])
1954 ppc
= (TTPOLYCURVE
*)((char *)pvBuf
+ needed
);
1955 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
1956 TT_PRIM_LINE
: TT_PRIM_QSPLINE
;
1961 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1965 while (point
<= outline
->contours
[contour
] &&
1966 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
1967 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
1969 /* At the end of a contour Windows adds the start point, but
1971 if (point
> outline
->contours
[contour
] &&
1972 !(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
1975 FTVectorToPOINTFX(&outline
->points
[first_pt
], &ppc
->apfx
[cpfx
]);
1978 else if (point
<= outline
->contours
[contour
] &&
1979 outline
->tags
[point
] & FT_Curve_Tag_On
)
1981 /* Add closing pt for bezier */
1983 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
1992 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
1994 if (pvBuf
) pph
->cb
= needed
- pph_start
;
2001 /* Convert the quadratic Beziers to cubic Beziers.
2002 The parametric eqn for a cubic Bezier is, from PLRM:
2003 r(t) = at^3 + bt^2 + ct + r0
2004 with the control points:
2009 A quadratic Beizer has the form:
2010 p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
2012 So equating powers of t leads to:
2013 r1 = 2/3 p1 + 1/3 p0
2014 r2 = 2/3 p1 + 1/3 p2
2015 and of course r0 = p0, r3 = p2
2018 int contour
, point
= 0, first_pt
;
2019 FT_Outline
*outline
= &ft_face
->glyph
->outline
;
2020 TTPOLYGONHEADER
*pph
;
2022 DWORD pph_start
, cpfx
, type
;
2023 FT_Vector cubic_control
[4];
2024 if (cjBuf
== 0) pvBuf
= NULL
;
2026 if (needsTransform
&& pvBuf
)
2029 FT_Outline_Transform(outline
, &transMat
);
2033 for (contour
= 0; contour
< outline
->n_contours
; contour
++)
2036 pph
= (TTPOLYGONHEADER
*)((char *)pvBuf
+ needed
);
2040 pph
->dwType
= TT_POLYGON_TYPE
;
2041 FTVectorToPOINTFX(&outline
->points
[point
], &pph
->pfxStart
);
2043 needed
+= sizeof(*pph
);
2045 while (point
<= outline
->contours
[contour
])
2047 ppc
= (TTPOLYCURVE
*)((char *)pvBuf
+ needed
);
2048 type
= (outline
->tags
[point
] & FT_Curve_Tag_On
) ?
2049 TT_PRIM_LINE
: TT_PRIM_CSPLINE
;
2053 if (type
== TT_PRIM_LINE
)
2056 FTVectorToPOINTFX(&outline
->points
[point
], &ppc
->apfx
[cpfx
]);
2062 /* Unlike QSPLINEs, CSPLINEs always have their endpoint
2065 /* FIXME: Possible optimization in endpoint calculation
2066 if there are two consecutive curves */
2067 cubic_control
[0] = outline
->points
[point
-1];
2068 if (!(outline
->tags
[point
-1] & FT_Curve_Tag_On
))
2070 cubic_control
[0].x
+= outline
->points
[point
].x
+ 1;
2071 cubic_control
[0].y
+= outline
->points
[point
].y
+ 1;
2072 cubic_control
[0].x
>>= 1;
2073 cubic_control
[0].y
>>= 1;
2075 if (point
+1 > outline
->contours
[contour
])
2076 cubic_control
[3] = outline
->points
[first_pt
];
2079 cubic_control
[3] = outline
->points
[point
+1];
2080 if (!(outline
->tags
[point
+1] & FT_Curve_Tag_On
))
2082 cubic_control
[3].x
+= outline
->points
[point
].x
+ 1;
2083 cubic_control
[3].y
+= outline
->points
[point
].y
+ 1;
2084 cubic_control
[3].x
>>= 1;
2085 cubic_control
[3].y
>>= 1;
2088 /* r1 = 1/3 p0 + 2/3 p1
2089 r2 = 1/3 p2 + 2/3 p1 */
2090 cubic_control
[1].x
= (2 * outline
->points
[point
].x
+ 1) / 3;
2091 cubic_control
[1].y
= (2 * outline
->points
[point
].y
+ 1) / 3;
2092 cubic_control
[2] = cubic_control
[1];
2093 cubic_control
[1].x
+= (cubic_control
[0].x
+ 1) / 3;
2094 cubic_control
[1].y
+= (cubic_control
[0].y
+ 1) / 3;
2095 cubic_control
[2].x
+= (cubic_control
[3].x
+ 1) / 3;
2096 cubic_control
[2].y
+= (cubic_control
[3].y
+ 1) / 3;
2099 FTVectorToPOINTFX(&cubic_control
[1], &ppc
->apfx
[cpfx
]);
2100 FTVectorToPOINTFX(&cubic_control
[2], &ppc
->apfx
[cpfx
+1]);
2101 FTVectorToPOINTFX(&cubic_control
[3], &ppc
->apfx
[cpfx
+2]);
2107 while (point
<= outline
->contours
[contour
] &&
2108 (outline
->tags
[point
] & FT_Curve_Tag_On
) ==
2109 (outline
->tags
[point
-1] & FT_Curve_Tag_On
));
2110 /* At the end of a contour Windows adds the start point,
2111 but only for Beziers and we've already done that. */
2112 if (point
<= outline
->contours
[contour
] &&
2113 outline
->tags
[point
] & FT_Curve_Tag_On
)
2115 /* This is the closing pt of a bezier, but we've already
2116 added it, so just inc point and carry on */
2124 needed
+= sizeof(*ppc
) + (cpfx
- 1) * sizeof(POINTFX
);
2126 if (pvBuf
) pph
->cb
= needed
- pph_start
;
2132 DPRINT1("Unsupported format %u\n", iFormat
);
2136 DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed
);
2142 TextIntGetTextExtentPoint(PDC dc
,
2155 FT_BitmapGlyph realglyph
;
2156 INT error
, n
, glyph_index
, i
, previous
;
2157 ULONGLONG TotalWidth
= 0;
2158 FT_CharMap charmap
, found
= NULL
;
2160 FT_Render_Mode RenderMode
;
2162 PMATRIX pmxWorldToDevice
;
2164 FontGDI
= ObjToGDI(TextObj
->Font
, FONT
);
2166 face
= FontGDI
->face
;
2173 if (face
->charmap
== NULL
)
2175 DPRINT("WARNING: No charmap selected!\n");
2176 DPRINT("This font face has %d charmaps\n", face
->num_charmaps
);
2178 for (n
= 0; n
< face
->num_charmaps
; n
++)
2180 charmap
= face
->charmaps
[n
];
2181 DPRINT("Found charmap encoding: %u\n", charmap
->encoding
);
2182 if (charmap
->encoding
!= 0)
2191 DPRINT1("WARNING: Could not find desired charmap!\n");
2194 error
= FT_Set_Charmap(face
, found
);
2197 DPRINT1("WARNING: Could not set the charmap!\n");
2201 Render
= IntIsFontRenderingEnabled();
2203 RenderMode
= IntGetFontRenderMode(&TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
);
2205 RenderMode
= FT_RENDER_MODE_MONO
;
2207 error
= FT_Set_Pixel_Sizes(face
,
2208 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfWidth
,
2209 /* FIXME: Should set character height if neg */
2210 (TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
== 0 ?
2211 dc
->ppdev
->devinfo
.lfDefaultFont
.lfHeight
: abs(TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
)));
2214 DPRINT1("Error in setting pixel sizes: %d\n", error
);
2217 /* Get the DC's world-to-device transformation matrix */
2218 pmxWorldToDevice
= DC_pmxWorldToDevice(dc
);
2219 FtSetCoordinateTransform(face
, pmxWorldToDevice
);
2221 use_kerning
= FT_HAS_KERNING(face
);
2224 for (i
= 0; i
< Count
; i
++)
2226 if (fl
& GTEF_INDICES
)
2227 glyph_index
= *String
;
2229 glyph_index
= FT_Get_Char_Index(face
, *String
);
2231 if (!(realglyph
= ftGdiGlyphCacheGet(face
, glyph_index
,
2232 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
,
2235 error
= FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
2238 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index
);
2242 glyph
= face
->glyph
;
2243 realglyph
= ftGdiGlyphCacheSet(face
,
2245 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
,
2251 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index
);
2256 /* Retrieve kerning distance */
2257 if (use_kerning
&& previous
&& glyph_index
)
2260 FT_Get_Kerning(face
, previous
, glyph_index
, 0, &delta
);
2261 TotalWidth
+= delta
.x
;
2264 TotalWidth
+= realglyph
->root
.advance
.x
>> 10;
2266 if (((TotalWidth
+ 32) >> 6) <= MaxExtent
&& NULL
!= Fit
)
2272 Dx
[i
] = (TotalWidth
+ 32) >> 6;
2275 previous
= glyph_index
;
2280 Size
->cx
= (TotalWidth
+ 32) >> 6;
2281 Size
->cy
= (TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
== 0 ?
2282 dc
->ppdev
->devinfo
.lfDefaultFont
.lfHeight
: abs(TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
));
2283 Size
->cy
= EngMulDiv(Size
->cy
, dc
->ppdev
->gdiinfo
.ulLogPixelsY
, 72);
2291 ftGdiGetTextCharsetInfo(
2293 LPFONTSIGNATURE lpSig
,
2297 UINT Ret
= DEFAULT_CHARSET
, i
;
2306 USHORT usACP
, usOEM
;
2308 pdcattr
= Dc
->pdcattr
;
2309 hFont
= pdcattr
->hlfntNew
;
2310 TextObj
= RealizeFontInit(hFont
);
2314 EngSetLastError(ERROR_INVALID_HANDLE
);
2317 FontGdi
= ObjToGDI(TextObj
->Font
, FONT
);
2318 Face
= FontGdi
->face
;
2319 TEXTOBJ_UnlockText(TextObj
);
2322 pOS2
= FT_Get_Sfnt_Table(Face
, ft_sfnt_os2
);
2324 memset(&fs
, 0, sizeof(FONTSIGNATURE
));
2327 fs
.fsCsb
[0] = pOS2
->ulCodePageRange1
;
2328 fs
.fsCsb
[1] = pOS2
->ulCodePageRange2
;
2329 fs
.fsUsb
[0] = pOS2
->ulUnicodeRange1
;
2330 fs
.fsUsb
[1] = pOS2
->ulUnicodeRange2
;
2331 fs
.fsUsb
[2] = pOS2
->ulUnicodeRange3
;
2332 fs
.fsUsb
[3] = pOS2
->ulUnicodeRange4
;
2333 if (pOS2
->version
== 0)
2337 if (FT_Get_First_Char( Face
, &dummy
) < 0x100)
2338 fs
.fsCsb
[0] |= FS_LATIN1
;
2340 fs
.fsCsb
[0] |= FS_SYMBOL
;
2343 DPRINT("Csb 1=%x 0=%x\n", fs
.fsCsb
[1],fs
.fsCsb
[0]);
2344 if (fs
.fsCsb
[0] == 0)
2345 { /* Let's see if we can find any interesting cmaps */
2346 for (i
= 0; i
< Face
->num_charmaps
; i
++)
2348 switch (Face
->charmaps
[i
]->encoding
)
2350 case FT_ENCODING_UNICODE
:
2351 case FT_ENCODING_APPLE_ROMAN
:
2352 fs
.fsCsb
[0] |= FS_LATIN1
;
2354 case FT_ENCODING_MS_SYMBOL
:
2355 fs
.fsCsb
[0] |= FS_SYMBOL
;
2364 RtlCopyMemory(lpSig
, &fs
, sizeof(FONTSIGNATURE
));
2367 RtlGetDefaultCodePage(&usACP
, &usOEM
);
2370 if (IntTranslateCharsetInfo(&cp
, &csi
, TCI_SRCCODEPAGE
))
2371 if (csi
.fs
.fsCsb
[0] & fs
.fsCsb
[0])
2374 Ret
= csi
.ciCharset
;
2378 for (i
= 0; i
< MAXTCIINDEX
; i
++)
2381 if (fs
.fsCsb
[0] & fs0
)
2383 if (IntTranslateCharsetInfo(&fs0
, &csi
, TCI_SRCFONTSIG
))
2387 Ret
= csi
.ciCharset
;
2391 DPRINT1("TCI failing on %x\n", fs0
);
2395 DPRINT("CharSet %u CodePage %u\n", csi
.ciCharset
, csi
.ciACP
);
2396 return (MAKELONG(csi
.ciACP
, csi
.ciCharset
));
2402 ftGetFontUnicodeRanges(PFONTGDI Font
, PGLYPHSET glyphset
)
2405 DWORD num_ranges
= 0;
2406 FT_Face face
= Font
->face
;
2408 if (face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
2410 FT_UInt glyph_code
= 0;
2411 FT_ULong char_code
, char_code_prev
;
2413 char_code_prev
= char_code
= FT_Get_First_Char(face
, &glyph_code
);
2415 DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
2416 face
->num_glyphs
, glyph_code
, char_code
);
2418 if (!glyph_code
) return 0;
2422 glyphset
->ranges
[0].wcLow
= (USHORT
)char_code
;
2423 glyphset
->ranges
[0].cGlyphs
= 0;
2424 glyphset
->cGlyphsSupported
= 0;
2430 if (char_code
< char_code_prev
)
2432 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
2435 if (char_code
- char_code_prev
> 1)
2440 glyphset
->ranges
[num_ranges
- 1].wcLow
= (USHORT
)char_code
;
2441 glyphset
->ranges
[num_ranges
- 1].cGlyphs
= 1;
2442 glyphset
->cGlyphsSupported
++;
2447 glyphset
->ranges
[num_ranges
- 1].cGlyphs
++;
2448 glyphset
->cGlyphsSupported
++;
2450 char_code_prev
= char_code
;
2451 char_code
= FT_Get_Next_Char(face
, char_code
, &glyph_code
);
2455 DPRINT1("Encoding %u not supported\n", face
->charmap
->encoding
);
2457 size
= sizeof(GLYPHSET
) + sizeof(WCRANGE
) * (num_ranges
- 1);
2460 glyphset
->cbThis
= size
;
2461 glyphset
->cRanges
= num_ranges
;
2469 ftGdiGetTextMetricsW(
2471 PTMW_INTERNAL ptmwi
)
2479 TT_HoriHeader
*pHori
;
2480 FT_WinFNT_HeaderRec Win
;
2482 NTSTATUS Status
= STATUS_SUCCESS
;
2486 EngSetLastError(STATUS_INVALID_PARAMETER
);
2490 if (!(dc
= DC_LockDc(hDC
)))
2492 EngSetLastError(ERROR_INVALID_HANDLE
);
2495 pdcattr
= dc
->pdcattr
;
2496 TextObj
= RealizeFontInit(pdcattr
->hlfntNew
);
2497 if (NULL
!= TextObj
)
2499 FontGDI
= ObjToGDI(TextObj
->Font
, FONT
);
2501 Face
= FontGDI
->face
;
2503 Error
= FT_Set_Pixel_Sizes(Face
,
2504 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfWidth
,
2505 /* FIXME: Should set character height if neg */
2506 (TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
== 0 ?
2507 dc
->ppdev
->devinfo
.lfDefaultFont
.lfHeight
: abs(TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
)));
2508 FtSetCoordinateTransform(Face
, DC_pmxWorldToDevice(dc
));
2512 DPRINT1("Error in setting pixel sizes: %u\n", Error
);
2513 Status
= STATUS_UNSUCCESSFUL
;
2517 Status
= STATUS_SUCCESS
;
2520 pOS2
= FT_Get_Sfnt_Table(FontGDI
->face
, ft_sfnt_os2
);
2523 DPRINT1("Can't find OS/2 table - not TT font?\n");
2524 Status
= STATUS_INTERNAL_ERROR
;
2527 pHori
= FT_Get_Sfnt_Table(FontGDI
->face
, ft_sfnt_hhea
);
2530 DPRINT1("Can't find HHEA table - not TT font?\n");
2531 Status
= STATUS_INTERNAL_ERROR
;
2534 Error
= FT_Get_WinFNT_Header(FontGDI
->face
, &Win
);
2538 if (NT_SUCCESS(Status
))
2540 FillTM(&ptmwi
->TextMetric
, FontGDI
, pOS2
, pHori
, !Error
? &Win
: 0);
2542 /* FIXME: Fill Diff member */
2543 RtlZeroMemory(&ptmwi
->Diff
, sizeof(ptmwi
->Diff
));
2546 TEXTOBJ_UnlockText(TextObj
);
2550 Status
= STATUS_INVALID_HANDLE
;
2554 if (!NT_SUCCESS(Status
))
2556 SetLastNtError(Status
);
2572 DWORD Result
= GDI_ERROR
;
2576 if (FT_IS_SFNT(FontGdi
->face
))
2579 Table
= Table
>> 24 | Table
<< 24 | (Table
>> 8 & 0xFF00) |
2580 (Table
<< 8 & 0xFF0000);
2582 if (!Buffer
) Size
= 0;
2587 FT_ULong Needed
= 0;
2589 Error
= FT_Load_Sfnt_Table(FontGdi
->face
, Table
, Offset
, NULL
, &Needed
);
2591 if ( !Error
&& Needed
< Size
) Size
= Needed
;
2593 if (!FT_Load_Sfnt_Table(FontGdi
->face
, Table
, Offset
, Buffer
, &Size
))
2602 static UINT FASTCALL
2603 GetFontScore(LOGFONTW
*LogFont
, PUNICODE_STRING FaceName
, PFONTGDI FontGDI
)
2605 ANSI_STRING EntryFaceNameA
;
2606 UNICODE_STRING EntryFaceNameW
;
2608 OUTLINETEXTMETRICW
*Otm
;
2613 RtlInitAnsiString(&EntryFaceNameA
, FontGDI
->face
->family_name
);
2614 Status
= RtlAnsiStringToUnicodeString(&EntryFaceNameW
, &EntryFaceNameA
, TRUE
);
2615 if (NT_SUCCESS(Status
))
2617 if ((LF_FACESIZE
- 1) * sizeof(WCHAR
) < EntryFaceNameW
.Length
)
2619 EntryFaceNameW
.Length
= (LF_FACESIZE
- 1) * sizeof(WCHAR
);
2620 EntryFaceNameW
.Buffer
[LF_FACESIZE
- 1] = L
'\0';
2622 if (0 == RtlCompareUnicodeString(FaceName
, &EntryFaceNameW
, TRUE
))
2626 RtlFreeUnicodeString(&EntryFaceNameW
);
2629 Size
= IntGetOutlineTextMetrics(FontGDI
, 0, NULL
);
2630 Otm
= ExAllocatePoolWithTag(PagedPool
, Size
, GDITAG_TEXT
);
2635 IntGetOutlineTextMetrics(FontGDI
, Size
, Otm
);
2637 if ((0 != LogFont
->lfItalic
&& 0 != Otm
->otmTextMetrics
.tmItalic
) ||
2638 (0 == LogFont
->lfItalic
&& 0 == Otm
->otmTextMetrics
.tmItalic
))
2642 if (LogFont
->lfWeight
!= FW_DONTCARE
)
2644 if (LogFont
->lfWeight
< Otm
->otmTextMetrics
.tmWeight
)
2646 WeightDiff
= Otm
->otmTextMetrics
.tmWeight
- LogFont
->lfWeight
;
2650 WeightDiff
= LogFont
->lfWeight
- Otm
->otmTextMetrics
.tmWeight
;
2652 Score
+= (1000 - WeightDiff
) / (1000 / 25);
2659 ExFreePoolWithTag(Otm
, GDITAG_TEXT
);
2664 static __inline VOID
2665 FindBestFontFromList(FONTOBJ
**FontObj
, UINT
*MatchScore
, LOGFONTW
*LogFont
,
2666 PUNICODE_STRING FaceName
, PLIST_ENTRY Head
)
2669 PFONT_ENTRY CurrentEntry
;
2672 ASSERT(FontObj
&& MatchScore
&& LogFont
&& FaceName
&& Head
);
2673 Entry
= Head
->Flink
;
2674 while (Entry
!= Head
)
2676 CurrentEntry
= (PFONT_ENTRY
) CONTAINING_RECORD(Entry
, FONT_ENTRY
, ListEntry
);
2678 FontGDI
= CurrentEntry
->Font
;
2681 Score
= GetFontScore(LogFont
, FaceName
, FontGDI
);
2682 if (*MatchScore
== 0 || *MatchScore
< Score
)
2684 *FontObj
= GDIToObj(FontGDI
, FONT
);
2685 *MatchScore
= Score
;
2687 Entry
= Entry
->Flink
;
2691 static __inline BOOLEAN
2692 SubstituteFontFamilyKey(PUNICODE_STRING FaceName
,
2695 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = {{0}};
2697 UNICODE_STRING Value
;
2699 RtlInitUnicodeString(&Value
, NULL
);
2701 QueryTable
[0].QueryRoutine
= NULL
;
2702 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_NOEXPAND
|
2703 RTL_QUERY_REGISTRY_REQUIRED
;
2704 QueryTable
[0].Name
= FaceName
->Buffer
;
2705 QueryTable
[0].EntryContext
= &Value
;
2706 QueryTable
[0].DefaultType
= REG_NONE
;
2707 QueryTable
[0].DefaultData
= NULL
;
2708 QueryTable
[0].DefaultLength
= 0;
2710 QueryTable
[1].QueryRoutine
= NULL
;
2711 QueryTable
[1].Name
= NULL
;
2713 Status
= RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT
,
2718 if (NT_SUCCESS(Status
))
2720 RtlFreeUnicodeString(FaceName
);
2724 return NT_SUCCESS(Status
);
2727 static __inline
void
2728 SubstituteFontFamily(PUNICODE_STRING FaceName
, UINT Level
)
2730 if (10 < Level
) /* Enough is enough */
2735 if (SubstituteFontFamilyKey(FaceName
, L
"FontSubstitutes"))
2737 SubstituteFontFamily(FaceName
, Level
+ 1);
2744 IntFontType(PFONTGDI Font
)
2746 PS_FontInfoRec psfInfo
;
2747 FT_ULong tmp_size
= 0;
2749 if (FT_HAS_MULTIPLE_MASTERS(Font
->face
))
2750 Font
->FontObj
.flFontType
|= FO_MULTIPLEMASTER
;
2751 if (FT_HAS_VERTICAL( Font
->face
))
2752 Font
->FontObj
.flFontType
|= FO_VERT_FACE
;
2753 if (FT_IS_SCALABLE( Font
->face
))
2754 Font
->FontObj
.flFontType
|= FO_TYPE_RASTER
;
2755 if (FT_IS_SFNT(Font
->face
))
2757 Font
->FontObj
.flFontType
|= FO_TYPE_TRUETYPE
;
2758 if (FT_Get_Sfnt_Table(Font
->face
, ft_sfnt_post
))
2759 Font
->FontObj
.flFontType
|= FO_POSTSCRIPT
;
2761 if (!FT_Get_PS_Font_Info(Font
->face
, &psfInfo
))
2763 Font
->FontObj
.flFontType
|= FO_POSTSCRIPT
;
2765 /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
2766 if (!FT_Load_Sfnt_Table(Font
->face
, FT_MAKE_TAG('C','F','F',' '), 0, NULL
, &tmp_size
))
2768 Font
->FontObj
.flFontType
|= (FO_CFF
|FO_POSTSCRIPT
);
2774 TextIntRealizeFont(HFONT FontHandle
, PTEXTOBJ pTextObj
)
2776 NTSTATUS Status
= STATUS_SUCCESS
;
2778 UNICODE_STRING FaceName
;
2779 PPROCESSINFO Win32Process
;
2784 TextObj
= TEXTOBJ_LockText(FontHandle
);
2785 if (NULL
== TextObj
)
2787 return STATUS_INVALID_HANDLE
;
2790 if (TextObj
->fl
& TEXTOBJECT_INIT
)
2792 TEXTOBJ_UnlockText(TextObj
);
2793 return STATUS_SUCCESS
;
2799 if (! RtlCreateUnicodeString(&FaceName
, TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
))
2801 if (!pTextObj
) TEXTOBJ_UnlockText(TextObj
);
2802 return STATUS_NO_MEMORY
;
2804 SubstituteFontFamily(&FaceName
, 0);
2806 TextObj
->Font
= NULL
;
2808 /* First search private fonts */
2809 Win32Process
= PsGetCurrentProcessWin32Process();
2810 IntLockProcessPrivateFonts(Win32Process
);
2811 FindBestFontFromList(&TextObj
->Font
, &MatchScore
,
2812 &TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
, &FaceName
,
2813 &Win32Process
->PrivateFontListHead
);
2814 IntUnLockProcessPrivateFonts(Win32Process
);
2816 /* Search system fonts */
2818 FindBestFontFromList(&TextObj
->Font
, &MatchScore
,
2819 &TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
, &FaceName
,
2821 IntUnLockGlobalFonts
;
2822 if (NULL
== TextObj
->Font
)
2824 DPRINT1("Requested font %S not found, no fonts loaded at all\n",
2825 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
);
2826 Status
= STATUS_NOT_FOUND
;
2830 PFONTGDI FontGdi
= ObjToGDI(TextObj
->Font
, FONT
);
2831 // Need hdev, when freetype is loaded need to create DEVOBJ for
2832 // Consumer and Producer.
2833 TextObj
->Font
->iUniq
= 1; // Now it can be cached.
2834 IntFontType(FontGdi
);
2835 FontGdi
->flType
= TextObj
->Font
->flFontType
;
2836 FontGdi
->Underline
= TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfUnderline
? 0xff : 0;
2837 FontGdi
->StrikeOut
= TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfStrikeOut
? 0xff : 0;
2838 TextObj
->fl
|= TEXTOBJECT_INIT
;
2839 Status
= STATUS_SUCCESS
;
2842 RtlFreeUnicodeString(&FaceName
);
2843 if (!pTextObj
) TEXTOBJ_UnlockText(TextObj
);
2845 ASSERT((NT_SUCCESS(Status
) ^ (NULL
== TextObj
->Font
)) != 0);
2855 POBJECT_NAME_INFORMATION NameInfo
,
2857 PUNICODE_STRING FileName
)
2860 OBJECT_ATTRIBUTES ObjectAttributes
;
2862 IO_STATUS_BLOCK IoStatusBlock
;
2865 InitializeObjectAttributes(&ObjectAttributes
,
2867 OBJ_CASE_INSENSITIVE
,
2871 Status
= ZwOpenFile(
2873 0, // FILE_READ_ATTRIBUTES,
2876 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
2879 if (!NT_SUCCESS(Status
))
2881 DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status
);
2885 Status
= ZwQueryObject(hFile
, ObjectNameInformation
, NameInfo
, Size
, &Desired
);
2887 if (!NT_SUCCESS(Status
))
2889 DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status
);
2898 IntGdiGetFontResourceInfo(
2899 PUNICODE_STRING FileName
,
2904 UNICODE_STRING EntryFileName
;
2905 POBJECT_NAME_INFORMATION NameInfo1
, NameInfo2
;
2906 PLIST_ENTRY ListEntry
;
2907 PFONT_ENTRY FontEntry
;
2908 FONTFAMILYINFO Info
;
2910 BOOL bFound
= FALSE
;
2912 /* Create buffer for full path name */
2913 Size
= sizeof(OBJECT_NAME_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
2914 NameInfo1
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_FINF
);
2917 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2921 /* Get the full path name */
2922 if (!IntGetFullFileName(NameInfo1
, Size
, FileName
))
2924 ExFreePoolWithTag(NameInfo1
, TAG_FINF
);
2928 /* Create a buffer for the entries' names */
2929 NameInfo2
= ExAllocatePoolWithTag(PagedPool
, Size
, TAG_FINF
);
2932 ExFreePoolWithTag(NameInfo1
, TAG_FINF
);
2933 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2937 /* Try to find the pathname in the global font list */
2939 for (ListEntry
= FontListHead
.Flink
;
2940 ListEntry
!= &FontListHead
;
2941 ListEntry
= ListEntry
->Flink
)
2943 FontEntry
= CONTAINING_RECORD(ListEntry
, FONT_ENTRY
, ListEntry
);
2944 if (FontEntry
->Font
->Filename
!= NULL
)
2946 RtlInitUnicodeString(&EntryFileName
, FontEntry
->Font
->Filename
);
2947 if (IntGetFullFileName(NameInfo2
, Size
, &EntryFileName
))
2949 if (RtlEqualUnicodeString(&NameInfo1
->Name
, &NameInfo2
->Name
, FALSE
))
2952 FontFamilyFillInfo(&Info
, FontEntry
->FaceName
.Buffer
, FontEntry
->Font
);
2959 IntUnLockGlobalFonts
;
2961 /* Free the buffers */
2962 ExFreePoolWithTag(NameInfo1
, TAG_FINF
);
2963 ExFreePool(NameInfo2
);
2965 if (!bFound
&& dwType
!= 5)
2967 /* Font could not be found in system table
2968 dwType == 5 will still handle this */
2974 case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
2975 *(DWORD
*)pBuffer
= 1;
2976 *pdwBytes
= sizeof(DWORD
);
2979 case 1: /* Copy the full font name */
2980 Size
= wcslen(Info
.EnumLogFontEx
.elfFullName
) + 1;
2981 Size
= min(Size
, LF_FULLFACESIZE
) * sizeof(WCHAR
);
2982 RtlCopyMemory(pBuffer
, Info
.EnumLogFontEx
.elfFullName
, Size
);
2983 // FIXME: Do we have to zeroterminate?
2987 case 2: /* Copy a LOGFONTW structure */
2988 Info
.EnumLogFontEx
.elfLogFont
.lfWidth
= 0;
2989 RtlCopyMemory(pBuffer
, &Info
.EnumLogFontEx
.elfLogFont
, sizeof(LOGFONTW
));
2990 *pdwBytes
= sizeof(LOGFONTW
);
2993 case 3: /* FIXME: What exactly is copied here? */
2994 *(DWORD
*)pBuffer
= 1;
2995 *pdwBytes
= sizeof(DWORD
*);
2998 case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
2999 *(BOOL
*)pBuffer
= !bFound
;
3000 *pdwBytes
= sizeof(BOOL
);
3013 ftGdiRealizationInfo(PFONTGDI Font
, PREALIZATION_INFO Info
)
3015 if (FT_HAS_FIXED_SIZES(Font
->face
))
3016 Info
->iTechnology
= RI_TECH_BITMAP
;
3019 if (FT_IS_SCALABLE(Font
->face
))
3020 Info
->iTechnology
= RI_TECH_SCALABLE
;
3022 Info
->iTechnology
= RI_TECH_FIXED
;
3024 Info
->iUniq
= Font
->FontObj
.iUniq
;
3025 Info
->dwUnknown
= -1;
3032 ftGdiGetKerningPairs( PFONTGDI Font
,
3034 LPKERNINGPAIR pKerningPair
)
3038 FT_Face face
= Font
->face
;
3040 if (FT_HAS_KERNING(face
) && face
->charmap
->encoding
== FT_ENCODING_UNICODE
)
3042 FT_UInt previous_index
= 0, glyph_index
= 0;
3043 FT_ULong char_code
, char_previous
;
3046 char_previous
= char_code
= FT_Get_First_Char(face
, &glyph_index
);
3052 if (previous_index
&& glyph_index
)
3054 FT_Get_Kerning(face
, previous_index
, glyph_index
, FT_KERNING_DEFAULT
, &delta
);
3056 if (pKerningPair
&& cPairs
)
3058 pKerningPair
[i
].wFirst
= char_previous
;
3059 pKerningPair
[i
].wSecond
= char_code
;
3060 pKerningPair
[i
].iKernAmount
= delta
.x
;
3062 if (i
== cPairs
) break;
3066 previous_index
= glyph_index
;
3067 char_previous
= char_code
;
3068 char_code
= FT_Get_Next_Char(face
, char_code
, &glyph_index
);
3076 ///////////////////////////////////////////////////////////////////////////
3078 // Functions needing sorting.
3080 ///////////////////////////////////////////////////////////////////////////
3082 NtGdiGetFontFamilyInfo(HDC Dc
,
3083 LPLOGFONTW UnsafeLogFont
,
3084 PFONTFAMILYINFO UnsafeInfo
,
3089 PFONTFAMILYINFO Info
;
3091 PPROCESSINFO Win32Process
;
3093 /* Make a safe copy */
3094 Status
= MmCopyFromCaller(&LogFont
, UnsafeLogFont
, sizeof(LOGFONTW
));
3095 if (! NT_SUCCESS(Status
))
3097 EngSetLastError(ERROR_INVALID_PARAMETER
);
3101 /* Allocate space for a safe copy */
3102 Info
= ExAllocatePoolWithTag(PagedPool
, Size
* sizeof(FONTFAMILYINFO
), GDITAG_TEXT
);
3105 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3109 /* Enumerate font families in the global list */
3112 if (! GetFontFamilyInfoForList(&LogFont
, Info
, &Count
, Size
, &FontListHead
) )
3114 IntUnLockGlobalFonts
;
3115 ExFreePoolWithTag(Info
, GDITAG_TEXT
);
3118 IntUnLockGlobalFonts
;
3120 /* Enumerate font families in the process local list */
3121 Win32Process
= PsGetCurrentProcessWin32Process();
3122 IntLockProcessPrivateFonts(Win32Process
);
3123 if (! GetFontFamilyInfoForList(&LogFont
, Info
, &Count
, Size
,
3124 &Win32Process
->PrivateFontListHead
))
3126 IntUnLockProcessPrivateFonts(Win32Process
);
3127 ExFreePoolWithTag(Info
, GDITAG_TEXT
);
3130 IntUnLockProcessPrivateFonts(Win32Process
);
3132 /* Enumerate font families in the registry */
3133 if (! GetFontFamilyInfoForSubstitutes(&LogFont
, Info
, &Count
, Size
))
3135 ExFreePoolWithTag(Info
, GDITAG_TEXT
);
3139 /* Return data to caller */
3142 Status
= MmCopyToCaller(UnsafeInfo
, Info
,
3143 (Count
< Size
? Count
: Size
) * sizeof(FONTFAMILYINFO
));
3144 if (! NT_SUCCESS(Status
))
3146 ExFreePoolWithTag(Info
, GDITAG_TEXT
);
3147 EngSetLastError(ERROR_INVALID_PARAMETER
);
3152 ExFreePoolWithTag(Info
, GDITAG_TEXT
);
3159 ScaleLong(LONG lValue
, PFLOATOBJ pef
)
3163 /* Check if we have scaling different from 1 */
3164 if (!FLOATOBJ_Equal(pef
, (PFLOATOBJ
)&gef1
))
3166 /* Need to multiply */
3167 FLOATOBJ_SetLong(&efTemp
, lValue
);
3168 FLOATOBJ_Mul(&efTemp
, pef
);
3169 lValue
= FLOATOBJ_GetLong(&efTemp
);
3182 IN OPTIONAL PRECTL lprc
,
3185 IN OPTIONAL LPINT Dx
,
3186 IN DWORD dwCodePage
)
3190 * Call EngTextOut, which does the real work (calling DrvTextOut where
3197 SURFACE
*psurf
= NULL
;
3198 int error
, glyph_index
, n
, i
;
3201 FT_BitmapGlyph realglyph
;
3202 LONGLONG TextLeft
, RealXStart
;
3203 ULONG TextTop
, previous
, BackgroundLeft
;
3204 FT_Bool use_kerning
;
3205 RECTL DestRect
, MaskRect
, DummyRect
= {0, 0, 0, 0};
3206 POINTL SourcePoint
, BrushOrigin
;
3207 HBITMAP HSourceGlyph
;
3208 SURFOBJ
*SourceGlyphSurf
;
3210 FT_CharMap found
= 0, charmap
;
3214 PTEXTOBJ TextObj
= NULL
;
3215 EXLATEOBJ exloRGB2Dst
, exloDst2RGB
;
3216 FT_Render_Mode RenderMode
;
3219 BOOL DoBreak
= FALSE
;
3221 PMATRIX pmxWorldToDevice
;
3222 LONG fixAscender
, fixDescender
;
3224 // TODO: Write test-cases to exactly match real Windows in different
3225 // bad parameters (e.g. does Windows check the DC or the RECT first?).
3226 dc
= DC_LockDc(hDC
);
3229 EngSetLastError(ERROR_INVALID_HANDLE
);
3232 if (dc
->dctype
== DC_TYPE_INFO
)
3235 /* Yes, Windows really returns TRUE in this case */
3239 pdcattr
= dc
->pdcattr
;
3241 if ((fuOptions
& ETO_OPAQUE
) || pdcattr
->jBkMode
== OPAQUE
)
3243 if (pdcattr
->ulDirty_
& DIRTY_BACKGROUND
)
3244 DC_vUpdateBackgroundBrush(dc
);
3247 /* Check if String is valid */
3248 if ((Count
> 0xFFFF) || (Count
> 0 && String
== NULL
))
3250 EngSetLastError(ERROR_INVALID_PARAMETER
);
3254 DxShift
= fuOptions
& ETO_PDY
? 1 : 0;
3256 if (PATH_IsPathOpen(dc
->dclevel
))
3258 if (!PATH_ExtTextOut( dc
,
3262 (const RECTL
*)lprc
,
3265 (const INT
*)Dx
)) goto fail
;
3269 if (lprc
&& (fuOptions
& (ETO_OPAQUE
| ETO_CLIPPED
)))
3271 IntLPtoDP(dc
, (POINT
*)lprc
, 2);
3276 IntLPtoDP(dc
, &Start
, 1);
3278 RealXStart
= (Start
.x
+ dc
->ptlDCOrig
.x
) << 6;
3279 YStart
= Start
.y
+ dc
->ptlDCOrig
.y
;
3288 if ((fuOptions
& ETO_OPAQUE
) && lprc
)
3290 DestRect
.left
= lprc
->left
;
3291 DestRect
.top
= lprc
->top
;
3292 DestRect
.right
= lprc
->right
;
3293 DestRect
.bottom
= lprc
->bottom
;
3295 DestRect
.left
+= dc
->ptlDCOrig
.x
;
3296 DestRect
.top
+= dc
->ptlDCOrig
.y
;
3297 DestRect
.right
+= dc
->ptlDCOrig
.x
;
3298 DestRect
.bottom
+= dc
->ptlDCOrig
.y
;
3300 DC_vPrepareDCsForBlit(dc
, DestRect
, NULL
, DestRect
);
3302 if (pdcattr
->ulDirty_
& DIRTY_BACKGROUND
)
3303 DC_vUpdateBackgroundBrush(dc
);
3306 &dc
->dclevel
.pSurface
->SurfObj
,
3309 dc
->rosdc
.CombinedClip
,
3314 &dc
->eboBackground
.BrushObject
,
3316 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY
));
3317 fuOptions
&= ~ETO_OPAQUE
;
3318 DC_vFinishBlit(dc
, NULL
);
3322 if (pdcattr
->jBkMode
== OPAQUE
)
3324 fuOptions
|= ETO_OPAQUE
;
3328 TextObj
= RealizeFontInit(pdcattr
->hlfntNew
);
3329 if (TextObj
== NULL
)
3334 FontObj
= TextObj
->Font
;
3336 FontGDI
= ObjToGDI(FontObj
, FONT
);
3340 face
= FontGDI
->face
;
3341 if (face
->charmap
== NULL
)
3343 DPRINT("WARNING: No charmap selected!\n");
3344 DPRINT("This font face has %d charmaps\n", face
->num_charmaps
);
3346 for (n
= 0; n
< face
->num_charmaps
; n
++)
3348 charmap
= face
->charmaps
[n
];
3349 DPRINT("Found charmap encoding: %u\n", charmap
->encoding
);
3350 if (charmap
->encoding
!= 0)
3358 DPRINT1("WARNING: Could not find desired charmap!\n");
3360 error
= FT_Set_Charmap(face
, found
);
3363 DPRINT1("WARNING: Could not set the charmap!\n");
3367 Render
= IntIsFontRenderingEnabled();
3369 RenderMode
= IntGetFontRenderMode(&TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
);
3371 RenderMode
= FT_RENDER_MODE_MONO
;
3373 error
= FT_Set_Pixel_Sizes(
3375 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfWidth
,
3376 /* FIXME: Should set character height if neg */
3377 (TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
== 0 ?
3378 dc
->ppdev
->devinfo
.lfDefaultFont
.lfHeight
: abs(TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
)));
3381 DPRINT1("Error in setting pixel sizes: %d\n", error
);
3386 pmxWorldToDevice
= DC_pmxWorldToDevice(dc
);
3387 FtSetCoordinateTransform(face
, pmxWorldToDevice
);
3390 * Process the vertical alignment and determine the yoff.
3393 fixAscender
= ScaleLong(face
->size
->metrics
.ascender
, &pmxWorldToDevice
->efM22
);
3394 fixDescender
= ScaleLong(face
->size
->metrics
.descender
, &pmxWorldToDevice
->efM22
);
3396 if (pdcattr
->lTextAlign
& TA_BASELINE
)
3398 else if (pdcattr
->lTextAlign
& TA_BOTTOM
)
3399 yoff
= -fixDescender
>> 6;
3401 yoff
= fixAscender
>> 6;
3403 use_kerning
= FT_HAS_KERNING(face
);
3407 * Process the horizontal alignment and modify XStart accordingly.
3410 if (pdcattr
->lTextAlign
& (TA_RIGHT
| TA_CENTER
))
3412 ULONGLONG TextWidth
= 0;
3413 LPCWSTR TempText
= String
;
3417 * Calculate width of the text.
3422 Start
= Count
< 2 ? 0 : Count
- 2;
3423 TextWidth
= Count
< 2 ? 0 : (Dx
[(Count
-2)<<DxShift
] << 6);
3429 TempText
= String
+ Start
;
3431 for (i
= Start
; i
< Count
; i
++)
3433 if (fuOptions
& ETO_GLYPH_INDEX
)
3434 glyph_index
= *TempText
;
3436 glyph_index
= FT_Get_Char_Index(face
, *TempText
);
3438 if (!(realglyph
= ftGdiGlyphCacheGet(face
, glyph_index
,
3439 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
,
3442 error
= FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
3445 DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", glyph_index
);
3448 glyph
= face
->glyph
;
3449 realglyph
= ftGdiGlyphCacheSet(face
,
3451 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
,
3457 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index
);
3463 /* Retrieve kerning distance */
3464 if (use_kerning
&& previous
&& glyph_index
)
3467 FT_Get_Kerning(face
, previous
, glyph_index
, 0, &delta
);
3468 TextWidth
+= delta
.x
;
3471 TextWidth
+= realglyph
->root
.advance
.x
>> 10;
3473 previous
= glyph_index
;
3479 if ((pdcattr
->lTextAlign
& TA_CENTER
) == TA_CENTER
)
3481 RealXStart
-= TextWidth
/ 2;
3485 RealXStart
-= TextWidth
;
3489 TextLeft
= RealXStart
;
3491 BackgroundLeft
= (RealXStart
+ 32) >> 6;
3493 /* Lock blit with a dummy rect */
3494 DC_vPrepareDCsForBlit(dc
, DummyRect
, NULL
, DummyRect
);
3496 psurf
= dc
->dclevel
.pSurface
;
3497 if(!psurf
) psurf
= psurfDefaultBitmap
;
3498 SurfObj
= &psurf
->SurfObj
;
3500 EXLATEOBJ_vInitialize(&exloRGB2Dst
, &gpalRGB
, psurf
->ppal
, 0, 0, 0);
3501 EXLATEOBJ_vInitialize(&exloDst2RGB
, psurf
->ppal
, &gpalRGB
, 0, 0, 0);
3503 if ((fuOptions
& ETO_OPAQUE
) && (dc
->pdcattr
->ulDirty_
& DIRTY_BACKGROUND
))
3504 DC_vUpdateBackgroundBrush(dc
) ;
3506 if(dc
->pdcattr
->ulDirty_
& DIRTY_TEXT
)
3507 DC_vUpdateTextBrush(dc
) ;
3510 * The main rendering loop.
3512 for (i
= 0; i
< Count
; i
++)
3514 if (fuOptions
& ETO_GLYPH_INDEX
)
3515 glyph_index
= *String
;
3517 glyph_index
= FT_Get_Char_Index(face
, *String
);
3519 if (!(realglyph
= ftGdiGlyphCacheGet(face
, glyph_index
,
3520 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
,
3523 error
= FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
3526 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index
);
3530 glyph
= face
->glyph
;
3531 realglyph
= ftGdiGlyphCacheSet(face
,
3533 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
,
3539 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index
);
3545 /* retrieve kerning distance and move pen position */
3546 if (use_kerning
&& previous
&& glyph_index
&& NULL
== Dx
)
3549 FT_Get_Kerning(face
, previous
, glyph_index
, 0, &delta
);
3550 TextLeft
+= delta
.x
;
3552 DPRINT("TextLeft: %I64d\n", TextLeft
);
3553 DPRINT("TextTop: %lu\n", TextTop
);
3554 DPRINT("Advance: %d\n", realglyph
->root
.advance
.x
);
3556 if (fuOptions
& ETO_OPAQUE
)
3558 DestRect
.left
= BackgroundLeft
;
3559 DestRect
.right
= (TextLeft
+ (realglyph
->root
.advance
.x
>> 10) + 32) >> 6;
3560 DestRect
.top
= TextTop
+ yoff
- ((fixAscender
+ 32) >> 6);
3561 DestRect
.bottom
= TextTop
+ yoff
+ ((32 - fixDescender
) >> 6);
3562 MouseSafetyOnDrawStart(dc
->ppdev
, DestRect
.left
, DestRect
.top
, DestRect
.right
, DestRect
.bottom
);
3567 dc
->rosdc
.CombinedClip
,
3572 &dc
->eboBackground
.BrushObject
,
3574 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY
));
3575 MouseSafetyOnDrawEnd(dc
->ppdev
);
3576 BackgroundLeft
= DestRect
.right
;
3580 DestRect
.left
= ((TextLeft
+ 32) >> 6) + realglyph
->left
;
3581 DestRect
.right
= DestRect
.left
+ realglyph
->bitmap
.width
;
3582 DestRect
.top
= TextTop
+ yoff
- realglyph
->top
;
3583 DestRect
.bottom
= DestRect
.top
+ realglyph
->bitmap
.rows
;
3585 bitSize
.cx
= realglyph
->bitmap
.width
;
3586 bitSize
.cy
= realglyph
->bitmap
.rows
;
3587 MaskRect
.right
= realglyph
->bitmap
.width
;
3588 MaskRect
.bottom
= realglyph
->bitmap
.rows
;
3591 * We should create the bitmap out of the loop at the biggest possible
3592 * glyph size. Then use memset with 0 to clear it and sourcerect to
3593 * limit the work of the transbitblt.
3596 HSourceGlyph
= EngCreateBitmap(bitSize
, realglyph
->bitmap
.pitch
,
3597 BMF_8BPP
, BMF_TOPDOWN
,
3598 realglyph
->bitmap
.buffer
);
3599 if ( !HSourceGlyph
)
3601 DPRINT1("WARNING: EngLockSurface() failed!\n");
3602 // FT_Done_Glyph(realglyph);
3606 SourceGlyphSurf
= EngLockSurface((HSURF
)HSourceGlyph
);
3607 if ( !SourceGlyphSurf
)
3609 EngDeleteSurface((HSURF
)HSourceGlyph
);
3610 DPRINT1("WARNING: EngLockSurface() failed!\n");
3616 * Use the font data as a mask to paint onto the DCs surface using a
3620 if (lprc
&& (fuOptions
& ETO_CLIPPED
) &&
3621 DestRect
.right
>= lprc
->right
+ dc
->ptlDCOrig
.x
)
3623 // We do the check '>=' instead of '>' to possibly save an iteration
3624 // through this loop, since it's breaking after the drawing is done,
3625 // and x is always incremented.
3626 DestRect
.right
= lprc
->right
+ dc
->ptlDCOrig
.x
;
3629 if (lprc
&& (fuOptions
& ETO_CLIPPED
) &&
3630 DestRect
.bottom
>= lprc
->bottom
+ dc
->ptlDCOrig
.y
)
3632 DestRect
.bottom
= lprc
->bottom
+ dc
->ptlDCOrig
.y
;
3634 MouseSafetyOnDrawStart(dc
->ppdev
, DestRect
.left
, DestRect
.top
, DestRect
.right
, DestRect
.bottom
);
3638 dc
->rosdc
.CombinedClip
,
3643 &dc
->eboText
.BrushObject
,
3645 MouseSafetyOnDrawEnd(dc
->ppdev
) ;
3647 EngUnlockSurface(SourceGlyphSurf
);
3648 EngDeleteSurface((HSURF
)HSourceGlyph
);
3657 TextLeft
+= realglyph
->root
.advance
.x
>> 10;
3658 DPRINT("New TextLeft: %I64d\n", TextLeft
);
3662 TextLeft
+= Dx
[i
<<DxShift
] << 6;
3663 DPRINT("New TextLeft2: %I64d\n", TextLeft
);
3668 TextTop
-= Dx
[2 * i
+ 1] << 6;
3671 previous
= glyph_index
;
3677 DC_vFinishBlit(dc
, NULL
) ;
3678 EXLATEOBJ_vCleanup(&exloRGB2Dst
);
3679 EXLATEOBJ_vCleanup(&exloDst2RGB
);
3680 if (TextObj
!= NULL
)
3681 TEXTOBJ_UnlockText(TextObj
);
3688 EXLATEOBJ_vCleanup(&exloRGB2Dst
);
3689 EXLATEOBJ_vCleanup(&exloDst2RGB
);
3691 if (TextObj
!= NULL
)
3692 TEXTOBJ_UnlockText(TextObj
);
3699 #define STACK_TEXT_BUFFER_SIZE 100
3707 IN OPTIONAL LPRECT UnsafeRect
,
3708 IN LPWSTR UnsafeString
,
3710 IN OPTIONAL LPINT UnsafeDx
,
3711 IN DWORD dwCodePage
)
3713 BOOL Result
= FALSE
;
3714 NTSTATUS Status
= STATUS_SUCCESS
;
3716 BYTE LocalBuffer
[STACK_TEXT_BUFFER_SIZE
];
3717 PVOID Buffer
= LocalBuffer
;
3718 LPWSTR SafeString
= NULL
;
3719 LPINT SafeDx
= NULL
;
3720 ULONG BufSize
, StringSize
, DxSize
= 0;
3722 /* Check if String is valid */
3723 if ((Count
> 0xFFFF) || (Count
> 0 && UnsafeString
== NULL
))
3725 EngSetLastError(ERROR_INVALID_PARAMETER
);
3731 /* Calculate buffer size for string and Dx values */
3732 BufSize
= StringSize
= Count
* sizeof(WCHAR
);
3735 /* If ETO_PDY is specified, we have pairs of INTs */
3736 DxSize
= (Count
* sizeof(INT
)) * (fuOptions
& ETO_PDY
? 2 : 1);
3740 /* Check if our local buffer is large enough */
3741 if (BufSize
> STACK_TEXT_BUFFER_SIZE
)
3743 /* It's not, allocate a temp buffer */
3744 Buffer
= ExAllocatePoolWithTag(PagedPool
, BufSize
, GDITAG_TEXT
);
3751 /* Probe and copy user mode data to the buffer */
3754 /* Put the Dx before the String to assure alignment of 4 */
3755 SafeString
= (LPWSTR
)(((ULONG_PTR
)Buffer
) + DxSize
);
3757 /* Probe and copy the string */
3758 ProbeForRead(UnsafeString
, StringSize
, 1);
3759 memcpy((PVOID
)SafeString
, UnsafeString
, StringSize
);
3761 /* If we have Dx values... */
3764 /* ... probe and copy them */
3766 ProbeForRead(UnsafeDx
, DxSize
, 1);
3767 memcpy(SafeDx
, UnsafeDx
, DxSize
);
3770 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3772 Status
= _SEH2_GetExceptionCode();
3775 if (!NT_SUCCESS(Status
))
3781 /* If we have a rect, copy it */
3786 ProbeForRead(UnsafeRect
, sizeof(RECT
), 1);
3787 SafeRect
= *UnsafeRect
;
3789 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3791 Status
= _SEH2_GetExceptionCode();
3794 if (!NT_SUCCESS(Status
))
3800 /* Finally call the internal routine */
3801 Result
= GreExtTextOutW(hDC
,
3812 /* If we allocated a buffer, free it */
3813 if (Buffer
!= LocalBuffer
)
3815 ExFreePoolWithTag(Buffer
, GDITAG_TEXT
);
3827 NtGdiGetCharABCWidthsW(
3831 IN OPTIONAL PWCHAR pwch
,
3836 LPABCFLOAT SafeBuffF
= NULL
;
3842 FT_CharMap charmap
, found
= NULL
;
3843 UINT i
, glyph_index
, BufferSize
;
3845 NTSTATUS Status
= STATUS_SUCCESS
;
3846 PMATRIX pmxWorldToDevice
;
3856 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3858 Status
= _SEH2_GetExceptionCode();
3862 if (!NT_SUCCESS(Status
))
3864 EngSetLastError(Status
);
3870 EngSetLastError(ERROR_INVALID_PARAMETER
);
3874 BufferSize
= Count
* sizeof(ABC
); // Same size!
3875 SafeBuff
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, GDITAG_TEXT
);
3876 if (!fl
) SafeBuffF
= (LPABCFLOAT
) SafeBuff
;
3877 if (SafeBuff
== NULL
)
3879 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3883 dc
= DC_LockDc(hDC
);
3886 ExFreePoolWithTag(SafeBuff
, GDITAG_TEXT
);
3887 EngSetLastError(ERROR_INVALID_HANDLE
);
3890 pdcattr
= dc
->pdcattr
;
3891 hFont
= pdcattr
->hlfntNew
;
3892 TextObj
= RealizeFontInit(hFont
);
3894 /* Get the DC's world-to-device transformation matrix */
3895 pmxWorldToDevice
= DC_pmxWorldToDevice(dc
);
3898 if (TextObj
== NULL
)
3900 ExFreePoolWithTag(SafeBuff
, GDITAG_TEXT
);
3901 EngSetLastError(ERROR_INVALID_HANDLE
);
3905 FontGDI
= ObjToGDI(TextObj
->Font
, FONT
);
3907 face
= FontGDI
->face
;
3908 if (face
->charmap
== NULL
)
3910 for (i
= 0; i
< face
->num_charmaps
; i
++)
3912 charmap
= face
->charmaps
[i
];
3913 if (charmap
->encoding
!= 0)
3922 DPRINT1("WARNING: Could not find desired charmap!\n");
3923 ExFreePoolWithTag(SafeBuff
, GDITAG_TEXT
);
3924 EngSetLastError(ERROR_INVALID_HANDLE
);
3929 FT_Set_Charmap(face
, found
);
3934 FT_Set_Pixel_Sizes(face
,
3935 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfWidth
,
3936 /* FIXME: Should set character height if neg */
3937 (TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
== 0 ?
3938 dc
->ppdev
->devinfo
.lfDefaultFont
.lfHeight
: abs(TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
)));
3939 FtSetCoordinateTransform(face
, pmxWorldToDevice
);
3941 for (i
= FirstChar
; i
< FirstChar
+Count
; i
++)
3943 int adv
, lsb
, bbx
, left
, right
;
3947 if (fl
& GCABCW_INDICES
)
3948 glyph_index
= pwch
[i
- FirstChar
];
3950 glyph_index
= FT_Get_Char_Index(face
, pwch
[i
- FirstChar
]);
3954 if (fl
& GCABCW_INDICES
)
3957 glyph_index
= FT_Get_Char_Index(face
, i
);
3959 FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
3961 left
= (INT
)face
->glyph
->metrics
.horiBearingX
& -64;
3962 right
= (INT
)((face
->glyph
->metrics
.horiBearingX
+ face
->glyph
->metrics
.width
) + 63) & -64;
3963 adv
= (face
->glyph
->advance
.x
+ 32) >> 6;
3965 // int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
3966 // DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
3969 bbx
= (right
- left
) >> 6;
3971 DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
3975 SafeBuffF
[i
- FirstChar
].abcfA
= (FLOAT
) lsb
;
3976 SafeBuffF
[i
- FirstChar
].abcfB
= (FLOAT
) bbx
;
3977 SafeBuffF
[i
- FirstChar
].abcfC
= (FLOAT
) (adv
- lsb
- bbx
);
3981 SafeBuff
[i
- FirstChar
].abcA
= lsb
;
3982 SafeBuff
[i
- FirstChar
].abcB
= bbx
;
3983 SafeBuff
[i
- FirstChar
].abcC
= adv
- lsb
- bbx
;
3987 TEXTOBJ_UnlockText(TextObj
);
3988 Status
= MmCopyToCaller(Buffer
, SafeBuff
, BufferSize
);
3989 if (! NT_SUCCESS(Status
))
3991 SetLastNtError(Status
);
3992 ExFreePoolWithTag(SafeBuff
, GDITAG_TEXT
);
3995 ExFreePoolWithTag(SafeBuff
, GDITAG_TEXT
);
3996 DPRINT("NtGdiGetCharABCWidths Worked!\n");
4009 IN OPTIONAL PWCHAR pwc
,
4013 NTSTATUS Status
= STATUS_SUCCESS
;
4015 PFLOAT SafeBuffF
= NULL
;
4021 FT_CharMap charmap
, found
= NULL
;
4022 UINT i
, glyph_index
, BufferSize
;
4024 PMATRIX pmxWorldToDevice
;
4034 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4036 Status
= _SEH2_GetExceptionCode();
4040 if (!NT_SUCCESS(Status
))
4042 EngSetLastError(Status
);
4046 BufferSize
= Count
* sizeof(INT
); // Same size!
4047 SafeBuff
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, GDITAG_TEXT
);
4048 if (!fl
) SafeBuffF
= (PFLOAT
) SafeBuff
;
4049 if (SafeBuff
== NULL
)
4051 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
4055 dc
= DC_LockDc(hDC
);
4058 ExFreePoolWithTag(SafeBuff
, GDITAG_TEXT
);
4059 EngSetLastError(ERROR_INVALID_HANDLE
);
4062 pdcattr
= dc
->pdcattr
;
4063 hFont
= pdcattr
->hlfntNew
;
4064 TextObj
= RealizeFontInit(hFont
);
4065 /* Get the DC's world-to-device transformation matrix */
4066 pmxWorldToDevice
= DC_pmxWorldToDevice(dc
);
4069 if (TextObj
== NULL
)
4071 ExFreePoolWithTag(SafeBuff
, GDITAG_TEXT
);
4072 EngSetLastError(ERROR_INVALID_HANDLE
);
4076 FontGDI
= ObjToGDI(TextObj
->Font
, FONT
);
4078 face
= FontGDI
->face
;
4079 if (face
->charmap
== NULL
)
4081 for (i
= 0; i
< face
->num_charmaps
; i
++)
4083 charmap
= face
->charmaps
[i
];
4084 if (charmap
->encoding
!= 0)
4093 DPRINT1("WARNING: Could not find desired charmap!\n");
4094 ExFreePool(SafeBuff
);
4095 EngSetLastError(ERROR_INVALID_HANDLE
);
4100 FT_Set_Charmap(face
, found
);
4105 FT_Set_Pixel_Sizes(face
,
4106 TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfWidth
,
4107 /* FIXME: Should set character height if neg */
4108 (TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
== 0 ?
4109 dc
->ppdev
->devinfo
.lfDefaultFont
.lfHeight
: abs(TextObj
->logfont
.elfEnumLogfontEx
.elfLogFont
.lfHeight
)));
4110 FtSetCoordinateTransform(face
, pmxWorldToDevice
);
4112 for (i
= FirstChar
; i
< FirstChar
+Count
; i
++)
4116 if (fl
& GCW_INDICES
)
4117 glyph_index
= pwc
[i
- FirstChar
];
4119 glyph_index
= FT_Get_Char_Index(face
, pwc
[i
- FirstChar
]);
4123 if (fl
& GCW_INDICES
)
4126 glyph_index
= FT_Get_Char_Index(face
, i
);
4128 FT_Load_Glyph(face
, glyph_index
, FT_LOAD_DEFAULT
);
4130 SafeBuffF
[i
- FirstChar
] = (FLOAT
) ((face
->glyph
->advance
.x
+ 32) >> 6);
4132 SafeBuff
[i
- FirstChar
] = (face
->glyph
->advance
.x
+ 32) >> 6;
4135 TEXTOBJ_UnlockText(TextObj
);
4136 MmCopyToCaller(Buffer
, SafeBuff
, BufferSize
);
4137 ExFreePoolWithTag(SafeBuff
, GDITAG_TEXT
);
4143 GreGetGlyphIndicesW(
4156 OUTLINETEXTMETRICW
*potm
;
4159 WCHAR DefChar
= 0xffff;
4160 PWSTR Buffer
= NULL
;
4163 if ((!pwc
) && (!pgi
)) return cwc
;
4165 dc
= DC_LockDc(hdc
);
4168 EngSetLastError(ERROR_INVALID_HANDLE
);
4171 pdcattr
= dc
->pdcattr
;
4172 hFont
= pdcattr
->hlfntNew
;
4173 TextObj
= RealizeFontInit(hFont
);
4177 EngSetLastError(ERROR_INVALID_HANDLE
);
4181 FontGDI
= ObjToGDI(TextObj
->Font
, FONT
);
4182 TEXTOBJ_UnlockText(TextObj
);
4184 Buffer
= ExAllocatePoolWithTag(PagedPool
, cwc
*sizeof(WORD
), GDITAG_TEXT
);
4187 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
4191 if (iMode
& GGI_MARK_NONEXISTING_GLYPHS
) DefChar
= 0x001f; /* Indicate non existence */
4194 Size
= IntGetOutlineTextMetrics(FontGDI
, 0, NULL
);
4195 potm
= ExAllocatePoolWithTag(PagedPool
, Size
, GDITAG_TEXT
);
4198 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
4202 IntGetOutlineTextMetrics(FontGDI
, Size
, potm
);
4203 DefChar
= potm
->otmTextMetrics
.tmDefaultChar
; // May need this.
4204 ExFreePoolWithTag(potm
, GDITAG_TEXT
);
4208 face
= FontGDI
->face
;
4210 for (i
= 0; i
< cwc
; i
++)
4212 Buffer
[i
] = FT_Get_Char_Index(face
, pwc
[i
]);
4215 if (DefChar
== 0xffff && FT_IS_SFNT(face
))
4217 TT_OS2
*pOS2
= FT_Get_Sfnt_Table(face
, ft_sfnt_os2
);
4218 DefChar
= (pOS2
->usDefaultChar
? FT_Get_Char_Index(face
, pOS2
->usDefaultChar
) : 0);
4220 Buffer
[i
] = DefChar
;
4226 RtlCopyMemory( pgi
, Buffer
, cwc
*sizeof(WORD
));
4229 if (Buffer
) ExFreePoolWithTag(Buffer
, GDITAG_TEXT
);
4239 NtGdiGetGlyphIndicesW(
4241 IN OPTIONAL LPWSTR UnSafepwc
,
4243 OUT OPTIONAL LPWORD UnSafepgi
,
4251 NTSTATUS Status
= STATUS_SUCCESS
;
4252 OUTLINETEXTMETRICW
*potm
;
4255 WCHAR DefChar
= 0xffff;
4256 PWSTR Buffer
= NULL
;
4259 if ((!UnSafepwc
) && (!UnSafepgi
)) return cwc
;
4261 dc
= DC_LockDc(hdc
);
4264 EngSetLastError(ERROR_INVALID_HANDLE
);
4267 pdcattr
= dc
->pdcattr
;
4268 hFont
= pdcattr
->hlfntNew
;
4269 TextObj
= RealizeFontInit(hFont
);
4273 EngSetLastError(ERROR_INVALID_HANDLE
);
4277 FontGDI
= ObjToGDI(TextObj
->Font
, FONT
);
4278 TEXTOBJ_UnlockText(TextObj
);
4280 Buffer
= ExAllocatePoolWithTag(PagedPool
, cwc
*sizeof(WORD
), GDITAG_TEXT
);
4283 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
4287 if (iMode
& GGI_MARK_NONEXISTING_GLYPHS
) DefChar
= 0x001f; /* Indicate non existence */
4290 Size
= IntGetOutlineTextMetrics(FontGDI
, 0, NULL
);
4291 potm
= ExAllocatePoolWithTag(PagedPool
, Size
, GDITAG_TEXT
);
4294 Status
= ERROR_NOT_ENOUGH_MEMORY
;
4297 IntGetOutlineTextMetrics(FontGDI
, Size
, potm
);
4298 DefChar
= potm
->otmTextMetrics
.tmDefaultChar
; // May need this.
4299 ExFreePoolWithTag(potm
, GDITAG_TEXT
);
4304 ProbeForRead(UnSafepwc
,
4308 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4310 Status
= _SEH2_GetExceptionCode();
4314 if (!NT_SUCCESS(Status
)) goto ErrorRet
;
4317 face
= FontGDI
->face
;
4319 if (DefChar
== 0xffff && FT_IS_SFNT(face
))
4321 TT_OS2
*pOS2
= FT_Get_Sfnt_Table(face
, ft_sfnt_os2
);
4322 DefChar
= (pOS2
->usDefaultChar
? FT_Get_Char_Index(face
, pOS2
->usDefaultChar
) : 0);
4325 for (i
= 0; i
< cwc
; i
++)
4327 Buffer
[i
] = FT_Get_Char_Index(face
, UnSafepwc
[i
]); // FIXME: Unsafe!
4330 Buffer
[i
] = DefChar
;
4338 ProbeForWrite(UnSafepgi
,
4341 RtlCopyMemory(UnSafepgi
,
4345 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4347 Status
= _SEH2_GetExceptionCode();
4352 ExFreePoolWithTag(Buffer
, GDITAG_TEXT
);
4353 if (NT_SUCCESS(Status
)) return cwc
;
4354 EngSetLastError(Status
);