diff --git a/reactos/bootdata/hivesft.inf b/reactos/bootdata/hivesft.inf index b2dcf0d67c0..9f2adb591eb 100644 --- a/reactos/bootdata/hivesft.inf +++ b/reactos/bootdata/hivesft.inf @@ -37,4 +37,10 @@ HKLM,"SOFTWARE\ReactOS\Windows NT\CurrentVersion\Winlogon","StartServices",0x000 HKLM,"SOFTWARE\ReactOS\Windows NT\CurrentVersion\Winlogon","StartGUI",0x00010001,0x00000000 HKLM,"SOFTWARE\ReactOS\Windows NT\CurrentVersion\Winlogon","Userinit",0x00020000,"%SystemRoot%\system32\userinit.exe" +; Font substitutes +; SysFontSubstitutes are also returned by EnumFontFamilies, FontSubstitutes aren't +HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SysFontSubstitutes","Arial",0x00000000,"Bitstream Vera Sans" +HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SysFontSubstitutes","Courier New",0x00000000,"Bitstream Vera Sans Mono" +HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SysFontSubstitutes","Times New Roman",0x00000000,"Bitstream Vera Serif" + ; EOF diff --git a/reactos/iface/addsys/w32ksvc.db b/reactos/iface/addsys/w32ksvc.db index c7d66aa2dbf..11c8d75ede3 100644 --- a/reactos/iface/addsys/w32ksvc.db +++ b/reactos/iface/addsys/w32ksvc.db @@ -66,8 +66,6 @@ NtGdiEndDoc 1 NtGdiEndPage 1 NtGdiEndPath 1 NtGdiEnumEnhMetaFile 5 -NtGdiEnumFontFamilies 4 -NtGdiEnumFontFamiliesEx 5 NtGdiEnumFonts 4 NtGdiEnumICMProfiles 3 NtGdiEnumMetaFile 4 @@ -126,6 +124,7 @@ NtGdiGetEnhMetaFileDescription 3 NtGdiGetEnhMetaFileHeader 3 NtGdiGetEnhMetaFilePaletteEntries 3 NtGdiGetEnhMetaFilePixelFormat 3 +NtGdiGetFontFamilyInfo 4 NtGdiGetFontLanguageInfo 1 #NtGdiGetFontResourceInfo ? NtGdiGetGlyphOutline 7 diff --git a/reactos/include/defines.h b/reactos/include/defines.h index 4efbc97f542..e71c52138cd 100644 --- a/reactos/include/defines.h +++ b/reactos/include/defines.h @@ -468,10 +468,12 @@ extern "C" { #define SYMBOL_CHARSET (2) #define SHIFTJIS_CHARSET (128) #define HANGEUL_CHARSET (129) +#define JOHAB_CHARSET (130) #define GB2312_CHARSET (134) #define CHINESEBIG5_CHARSET (136) #define GREEK_CHARSET (161) #define TURKISH_CHARSET (162) +#define VIETNAMESE_CHARSET (163) #define HEBREW_CHARSET (177) #define ARABIC_CHARSET (178) #define BALTIC_CHARSET (186) @@ -3276,6 +3278,18 @@ extern "C" { #define PAN_XHEIGHT_DUCKING_SMALL (5) #define PAN_XHEIGHT_DUCKING_STD (6) #define PAN_XHEIGHT_DUCKING_LARGE (7) +#define PANOSE_COUNT (10) +#define PAN_FAMILYTYPE_INDEX (0) +#define PAN_SERIFSTYLE_INDEX (1) +#define PAN_WEIGTH_INDEX (2) +#define PAN_PROPORTION_INDEX (3) +#define PAN_CONTRAST_INDEX (4) +#define PAN_STROKEVARIATION_INDEX (5) +#define PAN_ARMSTYLE_INDEX (6) +#define PAN_LETTERFORM_INDEX (7) +#define PAN_MIDLINE_INDEX (8) +#define PAN_XHEIGHT_INDEX (9) +#define PAN_CULTURE_LATIN (0) /* PALETTENTRY structure */ #define PC_EXPLICIT (2) @@ -4777,6 +4791,11 @@ extern "C" { #define TMPF_TRUETYPE (0x4) #define TMPF_DEVICE (0x8) +/* NEWTEXTMETRIC structure */ +#define NTM_ITALIC (0x01) +#define NTM_BOLD (0x20) +#define NTM_REGULAR (0x40) + /* CopyFileEx options */ #define COPY_FILE_FAIL_IF_EXISTS (1) diff --git a/reactos/include/structs.h b/reactos/include/structs.h index 8bc4bec495e..7029477246b 100644 --- a/reactos/include/structs.h +++ b/reactos/include/structs.h @@ -3634,13 +3634,13 @@ typedef struct tagNEWTEXTMETRICW { typedef_tident(NEWTEXTMETRIC) typedef struct tagNEWTEXTMETRICEXA { - NEWTEXTMETRICA ntmentm; - FONTSIGNATURE ntmeFontSignature; + NEWTEXTMETRICA ntmTm; + FONTSIGNATURE ntmFontSig; } NEWTEXTMETRICEXA; typedef struct tagNEWTEXTMETRICEXW { - NEWTEXTMETRICW ntmentm; - FONTSIGNATURE ntmeFontSignature; + NEWTEXTMETRICW ntmTm; + FONTSIGNATURE ntmFontSig; } NEWTEXTMETRICEXW; typedef_tident(NEWTEXTMETRICEX) diff --git a/reactos/include/win32k/font.h b/reactos/include/win32k/font.h new file mode 100644 index 00000000000..bea3c9f3ac6 --- /dev/null +++ b/reactos/include/win32k/font.h @@ -0,0 +1,26 @@ +/* $Id: font.h,v 1.1 2004/03/23 00:18:54 gvg Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: include/win32k/font.h + * PURPOSE: GDI32/Win32k font interface + * PROGRAMMER: + * + */ + +#ifndef WIN32K_FONT_H_INCLUDED +#define WIN32K_FONT_H_INCLUDED + +#include + +typedef struct tagFONTFAMILYINFO +{ + ENUMLOGFONTEXW EnumLogFontEx; + NEWTEXTMETRICEXW NewTextMetricEx; + DWORD FontType; +} FONTFAMILYINFO, *PFONTFAMILYINFO; + +int STDCALL NtGdiGetFontFamilyInfo(HDC Dc, LPLOGFONTW LogFont, PFONTFAMILYINFO Info, DWORD Size); +BOOL STDCALL NtGdiTranslateCharsetInfo(PDWORD Src, LPCHARSETINFO CSI, DWORD Flags); + +#endif /* WIN32K_FONT_H_INCLUDED */ diff --git a/reactos/include/win32k/kapi.h b/reactos/include/win32k/kapi.h index 5806a614806..0836fe64dee 100644 --- a/reactos/include/win32k/kapi.h +++ b/reactos/include/win32k/kapi.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/reactos/include/win32k/text.h b/reactos/include/win32k/text.h index 94c7c008d0a..8129784095b 100644 --- a/reactos/include/win32k/text.h +++ b/reactos/include/win32k/text.h @@ -53,21 +53,6 @@ NtGdiCreateScalableFontResource(DWORD Hidden, LPCWSTR FontFile, LPCWSTR CurrentPath); -int -STDCALL -NtGdiEnumFontFamilies(HDC hDC, - LPCWSTR Family, - FONTENUMPROCW EnumFontFamProc, - LPARAM lParam); - -int -STDCALL -NtGdiEnumFontFamiliesEx(HDC hDC, - LPLOGFONTW Logfont, - FONTENUMEXPROCW EnumFontFamExProc, - LPARAM lParam, - DWORD Flags); - int STDCALL NtGdiEnumFonts(HDC hDC, @@ -250,11 +235,5 @@ NtGdiTextOut(HDC hDC, LPCWSTR String, int Count); -UINT -STDCALL -NtGdiTranslateCharsetInfo(PDWORD Src, - LPCHARSETINFO CSI, - DWORD Flags); - #endif diff --git a/reactos/lib/gdi32/include/internal/font.h b/reactos/lib/gdi32/include/internal/font.h new file mode 100644 index 00000000000..35b0cf01da2 --- /dev/null +++ b/reactos/lib/gdi32/include/internal/font.h @@ -0,0 +1,21 @@ +/* $Id: font.h,v 1.1 2004/03/23 00:18:54 gvg Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/gdi32/include/internal/font.h + * PURPOSE: + * PROGRAMMER: + * + */ + +#ifndef GDI32_FONT_H_INCLUDED +#define GDI32_FONT_H_INCLUDED + +#include + +BOOL FASTCALL TextMetricW2A(TEXTMETRICA *tma, TEXTMETRICW *tmw); +BOOL FASTCALL NewTextMetricW2A(NEWTEXTMETRICA *tma, NEWTEXTMETRICW *tmw); +BOOL FASTCALL NewTextMetricExW2A(NEWTEXTMETRICEXA *tma, NEWTEXTMETRICEXW *tmw); + +#endif + diff --git a/reactos/lib/gdi32/makefile b/reactos/lib/gdi32/makefile index e944af61166..86831eac0e3 100644 --- a/reactos/lib/gdi32/makefile +++ b/reactos/lib/gdi32/makefile @@ -1,4 +1,4 @@ -# $Id: makefile,v 1.35 2003/11/16 22:44:39 sedwards Exp $ +# $Id: makefile,v 1.36 2004/03/23 00:18:54 gvg Exp $ PATH_TO_TOP = ../.. @@ -38,6 +38,7 @@ OBJECTS_OBJECTS = \ objects/clip.o \ objects/dc.o \ objects/fillshap.o \ + objects/font.o \ objects/line.o \ objects/linedda.o \ objects/metafile.o \ diff --git a/reactos/lib/gdi32/misc/stubs.c b/reactos/lib/gdi32/misc/stubs.c index 8a587a9a417..376399cc06f 100644 --- a/reactos/lib/gdi32/misc/stubs.c +++ b/reactos/lib/gdi32/misc/stubs.c @@ -1,4 +1,4 @@ -/* $Id: stubs.c,v 1.49 2004/02/14 00:31:38 sedwards Exp $ +/* $Id: stubs.c,v 1.50 2004/03/23 00:18:54 gvg Exp $ * * reactos/lib/gdi32/misc/stubs.c * @@ -380,22 +380,6 @@ GetTextCharsetInfo( } -/* - * @unimplemented - */ -BOOL -STDCALL -TranslateCharsetInfo( - DWORD FAR *lpSrc, - LPCHARSETINFO lpCs, - DWORD dwFlags - ) -{ - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - - /* * @unimplemented */ diff --git a/reactos/lib/gdi32/misc/stubsa.c b/reactos/lib/gdi32/misc/stubsa.c index 106bb36530f..531307de99f 100644 --- a/reactos/lib/gdi32/misc/stubsa.c +++ b/reactos/lib/gdi32/misc/stubsa.c @@ -1,4 +1,4 @@ -/* $Id: stubsa.c,v 1.27 2004/01/24 08:23:12 ekohl Exp $ +/* $Id: stubsa.c,v 1.28 2004/03/23 00:18:54 gvg Exp $ * * reactos/lib/gdi32/misc/stubs.c * @@ -175,66 +175,6 @@ DeviceCapabilitiesExA( } -/* - * @unimplemented - */ -int -STDCALL -EnumFontFamiliesExA ( - HDC hdc, - LPLOGFONTA lpLogFont, - FONTENUMEXPROCA lpEnumFontFamProc, - LPARAM lParam, - DWORD dwFlags - ) -{ - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -#if 0 - LOGFONTW LogFontW; - - RosRtlLogFontA2W ( &LogFontW, lpLogFont ); - - /* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */ - return NtGdiEnumFontFamiliesEx ( hdc, &LogFontW, lpEnumFontFamProc, lParam, dwFlags ); -#endif -} - - -/* - * @unimplemented - */ -int -STDCALL -EnumFontFamiliesA( - HDC hdc, - LPCSTR lpszFamily, - FONTENUMPROCA lpEnumFontFamProc, - LPARAM lParam - ) -{ - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -#if 0 - NTSTATUS Status; - LPWSTR lpszFamilyW; - int rc = 0; - - Status = HEAP_strdupA2W ( &lpszFamilyW, lpszFamily ); - if (!NT_SUCCESS (Status)) - SetLastError (RtlNtStatusToDosError(Status)); - else - { - rc = NtGdiEnumFontFamilies ( hdc, lpszFamilyW, lpEnumFontFamProc, lParam ); - - HEAP_free ( lpszFamilyW ); - } - - return rc; -#endif -} - - /* * @implemented */ diff --git a/reactos/lib/gdi32/misc/stubsw.c b/reactos/lib/gdi32/misc/stubsw.c index b22e8087e76..be9db44c9ae 100644 --- a/reactos/lib/gdi32/misc/stubsw.c +++ b/reactos/lib/gdi32/misc/stubsw.c @@ -1,4 +1,4 @@ -/* $Id: stubsw.c,v 1.24 2004/01/24 08:23:12 ekohl Exp $ +/* $Id: stubsw.c,v 1.25 2004/03/23 00:18:54 gvg Exp $ * * reactos/lib/gdi32/misc/stubs.c * @@ -112,49 +112,6 @@ DeviceCapabilitiesExW( } -/* - * @unimplemented - */ -int -STDCALL -EnumFontFamiliesExW( - HDC hdc, - LPLOGFONTW lpLogFont, - FONTENUMEXPROCW lpEnumFontFamProc, - LPARAM lParam, - DWORD dwFlags - ) -{ -#if 0 - return NtGdiEnumFontFamiliesEx ( hdc, lpLogFont, lpEnumFontFamProc, lParam, dwFlags ); -#else - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -#endif -} - - -/* - * @unimplemented - */ -int -STDCALL -EnumFontFamiliesW( - HDC hdc, - LPCWSTR lpszFamily, - FONTENUMPROCW lpEnumFontFamProc, - LPARAM lParam - ) -{ -#if 0 - return NtGdiEnumFontFamilies ( hdc, lpszFamily, lpEnumFontFamProc, lParam ); -#else - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -#endif -} - - /* * @unimplemented */ diff --git a/reactos/lib/gdi32/objects/font.c b/reactos/lib/gdi32/objects/font.c new file mode 100644 index 00000000000..f7f301d6ac2 --- /dev/null +++ b/reactos/lib/gdi32/objects/font.c @@ -0,0 +1,332 @@ +/* $Id: font.c,v 1.1 2004/03/23 00:18:54 gvg Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/gdi32/object/font.c + * PURPOSE: + * PROGRAMMER: + * + */ + +#ifdef UNICODE +#undef UNICODE +#endif + +#include +#include +#include +#include + +#define NDEBUG +#include + +#define INITIAL_FAMILY_COUNT 64 + +static BOOL FASTCALL +MetricsCharConvert(WCHAR w, CHAR *b) + { + UNICODE_STRING WString; + WCHAR WBuf[2]; + ANSI_STRING AString; + CHAR ABuf[2]; + NTSTATUS Status; + + if (L'\0' == w) + { + *b = '\0'; + } + else + { + WBuf[0] = w; + WBuf[1] = L'\0'; + RtlInitUnicodeString(&WString, WBuf); + ABuf[0] = '*'; + ABuf[1] = L'\0'; + RtlInitAnsiString(&AString, ABuf); + + Status = RtlUnicodeStringToAnsiString(&AString, &WString, FALSE); + if (! NT_SUCCESS(Status)) + { + SetLastError(RtlNtStatusToDosError(Status)); + return FALSE; + } + *b = ABuf[0]; + } + + return TRUE; +} + +BOOL FASTCALL +TextMetricW2A(TEXTMETRICA *tma, TEXTMETRICW *tmw) +{ + UNICODE_STRING WString; + WCHAR WBuf[256]; + ANSI_STRING AString; + CHAR ABuf[256]; + UINT Letter; + NTSTATUS Status; + + tma->tmHeight = tmw->tmHeight; + tma->tmAscent = tmw->tmAscent; + tma->tmDescent = tmw->tmDescent; + tma->tmInternalLeading = tmw->tmInternalLeading; + tma->tmExternalLeading = tmw->tmExternalLeading; + tma->tmAveCharWidth = tmw->tmAveCharWidth; + tma->tmMaxCharWidth = tmw->tmMaxCharWidth; + tma->tmWeight = tmw->tmWeight; + tma->tmOverhang = tmw->tmOverhang; + tma->tmDigitizedAspectX = tmw->tmDigitizedAspectX; + tma->tmDigitizedAspectY = tmw->tmDigitizedAspectY; + + /* The Unicode FirstChar/LastChar need not correspond to the ANSI + FirstChar/LastChar. For example, if the font contains glyphs for + letters A-Z and an accented version of the letter e, the Unicode + FirstChar would be A and the Unicode LastChar would be the accented + e. If you just translate those to ANSI, the range would become + letters A-E instead of A-Z. + We translate all possible ANSI chars to Unicode and find the first + and last translated character which fall into the Unicode FirstChar/ + LastChar range and return the corresponding ANSI char. */ + + /* Setup an Ansi string containing all possible letters (note: skip '\0' at + the beginning since that would be interpreted as end-of-string, handle + '\0' special later */ + for (Letter = 1; Letter < 256; Letter++) + { + ABuf[Letter - 1] = (CHAR) Letter; + WBuf[Letter - 1] = L' '; + } + ABuf[255] = '\0'; + WBuf[255] = L'\0'; + RtlInitAnsiString(&AString, ABuf); + RtlInitUnicodeString(&WString, WBuf); + + /* Find the corresponding Unicode characters */ + Status = RtlAnsiStringToUnicodeString(&WString, &AString, FALSE); + if (! NT_SUCCESS(Status)) + { + SetLastError(RtlNtStatusToDosError(Status)); + return FALSE; + } + + /* Scan for the first ANSI character which maps to an Unicode character + in the range */ + tma->tmFirstChar = '\0'; + if (L'\0' != tmw->tmFirstChar) + { + for (Letter = 1; Letter < 256; Letter++) + { + if (tmw->tmFirstChar <= WBuf[Letter - 1] && + WBuf[Letter - 1] <= tmw->tmLastChar) + { + tma->tmFirstChar = (CHAR) Letter; + break; + } + } + } + + /* Scan for the last ANSI character which maps to an Unicode character + in the range */ + tma->tmLastChar = '\0'; + if (L'\0' != tmw->tmLastChar) + { + for (Letter = 255; 0 < Letter; Letter--) + { + if (tmw->tmFirstChar <= WBuf[Letter - 1] && + WBuf[Letter - 1] <= tmw->tmLastChar) + { + tma->tmLastChar = (CHAR) Letter; + break; + } + } + } + + if (! MetricsCharConvert(tmw->tmDefaultChar, &tma->tmDefaultChar) || + ! MetricsCharConvert(tmw->tmBreakChar, &tma->tmBreakChar)) + { + return FALSE; + } + + tma->tmItalic = tmw->tmItalic; + tma->tmUnderlined = tmw->tmUnderlined; + tma->tmStruckOut = tmw->tmStruckOut; + tma->tmPitchAndFamily = tmw->tmPitchAndFamily; + tma->tmCharSet = tmw->tmCharSet; + + return TRUE; +} + +BOOL FASTCALL +NewTextMetricW2A(NEWTEXTMETRICA *tma, NEWTEXTMETRICW *tmw) +{ + if (! TextMetricW2A((TEXTMETRICA *) tma, (TEXTMETRICW *) tmw)) + { + return FALSE; + } + + tma->ntmFlags = tmw->ntmFlags; + tma->ntmSizeEM = tmw->ntmSizeEM; + tma->ntmCellHeight = tmw->ntmCellHeight; + tma->ntmAvgWidth = tmw->ntmAvgWidth; + + return TRUE; +} + +BOOL FASTCALL +NewTextMetricExW2A(NEWTEXTMETRICEXA *tma, NEWTEXTMETRICEXW *tmw) +{ + if (! NewTextMetricW2A(&tma->ntmTm, &tmw->ntmTm)) + { + return FALSE; + } + + tma->ntmFontSig = tmw->ntmFontSig; + + return TRUE; +} + +/* + * @implemented + */ +BOOL +STDCALL +TranslateCharsetInfo(DWORD *Src, LPCHARSETINFO Cs, DWORD Flags) +{ + return NtGdiTranslateCharsetInfo(Src, Cs, Flags); +} + +static int FASTCALL +IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam, + BOOL Unicode) +{ + int FontFamilyCount; + unsigned FontFamilySize; + PFONTFAMILYINFO Info; + int Ret; + unsigned i; + ENUMLOGFONTEXA EnumLogFontExA; + NEWTEXTMETRICEXA NewTextMetricExA; + + Info = RtlAllocateHeap(GetProcessHeap(), 0, + INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO)); + if (NULL == Info) + { + return 0; + } + FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, INITIAL_FAMILY_COUNT); + if (FontFamilyCount < 0) + { + RtlFreeHeap(GetProcessHeap(), 0, Info); + return 0; + } + if (INITIAL_FAMILY_COUNT < FontFamilyCount) + { + FontFamilySize = FontFamilyCount; + RtlFreeHeap(GetProcessHeap(), 0, Info); + Info = RtlAllocateHeap(GetProcessHeap(), 0, + FontFamilyCount * sizeof(FONTFAMILYINFO)); + if (NULL == Info) + { + return 0; + } + FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, FontFamilySize); + if (FontFamilyCount < 0 || FontFamilySize < FontFamilyCount) + { + RtlFreeHeap(GetProcessHeap(), 0, Info); + return 0; + } + } + + for (i = 0; i < FontFamilyCount; i++) + { + if (Unicode) + { + Ret = ((FONTENUMEXPROCW) EnumProc)(&Info[i].EnumLogFontEx, &Info[i].NewTextMetricEx, + Info[i].FontType, lParam); + } + else + { + RosRtlLogFontW2A(&EnumLogFontExA.elfLogFont, &Info[i].EnumLogFontEx.elfLogFont); + WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfFullName, -1, + EnumLogFontExA.elfFullName, LF_FULLFACESIZE, NULL, NULL); + WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfStyle, -1, + EnumLogFontExA.elfStyle, LF_FACESIZE, NULL, NULL); + WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfScript, -1, + EnumLogFontExA.elfScript, LF_FACESIZE, NULL, NULL); + NewTextMetricExW2A(&NewTextMetricExA, + &Info[i].NewTextMetricEx); + Ret = ((FONTENUMEXPROCA) EnumProc)(&EnumLogFontExA, &NewTextMetricExA, + Info[i].FontType, lParam); + } + } + + RtlFreeHeap(GetProcessHeap(), 0, Info); + + return Ret; +} + +/* + * @implemented + */ +int STDCALL +EnumFontFamiliesExW(HDC Dc, LPLOGFONTW LogFont, FONTENUMEXPROCW EnumFontFamProc, + LPARAM lParam, DWORD Flags) +{ + return IntEnumFontFamilies(Dc, LogFont, EnumFontFamProc, lParam, TRUE); +} + + +/* + * @implemented + */ +int STDCALL +EnumFontFamiliesW(HDC Dc, LPCWSTR Family, FONTENUMPROCW EnumFontFamProc, + LPARAM lParam) +{ + LOGFONTW LogFont; + + ZeroMemory(&LogFont, sizeof(LOGFONTW)); + LogFont.lfCharSet = DEFAULT_CHARSET; + if (NULL != Family) + { + lstrcpynW(LogFont.lfFaceName, Family, LF_FACESIZE); + } + + return IntEnumFontFamilies(Dc, &LogFont, EnumFontFamProc, lParam, TRUE); +} + + +/* + * @implemented + */ +int STDCALL +EnumFontFamiliesExA (HDC Dc, LPLOGFONTA LogFont, FONTENUMEXPROCA EnumFontFamProc, + LPARAM lParam, DWORD dwFlags) +{ + LOGFONTW LogFontW; + + RosRtlLogFontA2W(&LogFontW, LogFont); + + /* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */ + return IntEnumFontFamilies(Dc, &LogFontW, EnumFontFamProc, lParam, FALSE); +} + + +/* + * @implemented + */ +int STDCALL +EnumFontFamiliesA(HDC Dc, LPCSTR Family, FONTENUMPROCA EnumFontFamProc, + LPARAM lParam) +{ + LOGFONTW LogFont; + + ZeroMemory(&LogFont, sizeof(LOGFONTW)); + LogFont.lfCharSet = DEFAULT_CHARSET; + if (NULL != Family) + { + MultiByteToWideChar(CP_THREAD_ACP, 0, Family, -1, LogFont.lfFaceName, LF_FACESIZE); + } + + return IntEnumFontFamilies(Dc, &LogFont, EnumFontFamProc, lParam, FALSE); +} diff --git a/reactos/lib/gdi32/objects/text.c b/reactos/lib/gdi32/objects/text.c index 56de5c6014e..459e2a7e807 100644 --- a/reactos/lib/gdi32/objects/text.c +++ b/reactos/lib/gdi32/objects/text.c @@ -7,6 +7,7 @@ #include #include #include +#include /* @@ -78,41 +79,6 @@ SetTextColor(HDC hDC, COLORREF color) } -static BOOL -MetricsCharConvert(WCHAR w, CHAR *b) - { - UNICODE_STRING WString; - WCHAR WBuf[2]; - ANSI_STRING AString; - CHAR ABuf[2]; - NTSTATUS Status; - - if (L'\0' == w) - { - *b = '\0'; - } - else - { - WBuf[0] = w; - WBuf[1] = L'\0'; - RtlInitUnicodeString(&WString, WBuf); - ABuf[0] = '*'; - ABuf[1] = L'\0'; - RtlInitAnsiString(&AString, ABuf); - - Status = RtlUnicodeStringToAnsiString(&AString, &WString, FALSE); - if (! NT_SUCCESS(Status)) - { - SetLastError(RtlNtStatusToDosError(Status)); - return FALSE; - } - *b = ABuf[0]; - } - - return TRUE; - } - - /* * @implemented */ @@ -124,106 +90,13 @@ GetTextMetricsA( ) { TEXTMETRICW tmw; - UNICODE_STRING WString; - WCHAR WBuf[256]; - ANSI_STRING AString; - CHAR ABuf[256]; - UINT Letter; - NTSTATUS Status; if (! NtGdiGetTextMetrics(hdc, &tmw)) { return FALSE; } - tm->tmHeight = tmw.tmHeight; - tm->tmAscent = tmw.tmAscent; - tm->tmDescent = tmw.tmDescent; - tm->tmInternalLeading = tmw.tmInternalLeading; - tm->tmExternalLeading = tmw.tmExternalLeading; - tm->tmAveCharWidth = tmw.tmAveCharWidth; - tm->tmMaxCharWidth = tmw.tmMaxCharWidth; - tm->tmWeight = tmw.tmWeight; - tm->tmOverhang = tmw.tmOverhang; - tm->tmDigitizedAspectX = tmw.tmDigitizedAspectX; - tm->tmDigitizedAspectY = tmw.tmDigitizedAspectY; - - /* The Unicode FirstChar/LastChar need not correspond to the ANSI - FirstChar/LastChar. For example, if the font contains glyphs for - letters A-Z and an accented version of the letter e, the Unicode - FirstChar would be A and the Unicode LastChar would be the accented - e. If you just translate those to ANSI, the range would become - letters A-E instead of A-Z. - We translate all possible ANSI chars to Unicode and find the first - and last translated character which fall into the Unicode FirstChar/ - LastChar range and return the corresponding ANSI char. */ - - /* Setup an Ansi string containing all possible letters (note: skip '\0' at - the beginning since that would be interpreted as end-of-string, handle - '\0' special later */ - for (Letter = 1; Letter < 256; Letter++) - { - ABuf[Letter - 1] = (CHAR) Letter; - WBuf[Letter - 1] = L' '; - } - ABuf[255] = '\0'; - WBuf[255] = L'\0'; - RtlInitAnsiString(&AString, ABuf); - RtlInitUnicodeString(&WString, WBuf); - - /* Find the corresponding Unicode characters */ - Status = RtlAnsiStringToUnicodeString(&WString, &AString, FALSE); - if (! NT_SUCCESS(Status)) - { - SetLastError(RtlNtStatusToDosError(Status)); - return FALSE; - } - - /* Scan for the first ANSI character which maps to an Unicode character - in the range */ - tm->tmFirstChar = '\0'; - if (L'\0' != tmw.tmFirstChar) - { - for (Letter = 1; Letter < 256; Letter++) - { - if (tmw.tmFirstChar <= WBuf[Letter - 1] && - WBuf[Letter - 1] <= tmw.tmLastChar) - { - tm->tmFirstChar = (CHAR) Letter; - break; - } - } - } - - /* Scan for the last ANSI character which maps to an Unicode character - in the range */ - tm->tmLastChar = '\0'; - if (L'\0' != tmw.tmLastChar) - { - for (Letter = 255; 0 < Letter; Letter--) - { - if (tmw.tmFirstChar <= WBuf[Letter - 1] && - WBuf[Letter - 1] <= tmw.tmLastChar) - { - tm->tmLastChar = (CHAR) Letter; - break; - } - } - } - - if (! MetricsCharConvert(tmw.tmDefaultChar, &tm->tmDefaultChar) || - ! MetricsCharConvert(tmw.tmBreakChar, &tm->tmBreakChar)) - { - return FALSE; - } - - tm->tmItalic = tmw.tmItalic; - tm->tmUnderlined = tmw.tmUnderlined; - tm->tmStruckOut = tmw.tmStruckOut; - tm->tmPitchAndFamily = tmw.tmPitchAndFamily; - tm->tmCharSet = tmw.tmCharSet; - - return TRUE; + return TextMetricW2A(tm, &tmw); } @@ -237,7 +110,7 @@ GetTextMetricsW( LPTEXTMETRICW tm ) { - return NtGdiGetTextMetrics(hdc, tm); + return NtGdiGetTextMetrics(hdc, tm); } diff --git a/reactos/subsys/win32k/objects/text.c b/reactos/subsys/win32k/objects/text.c index b234d33940d..b890f7528a7 100644 --- a/reactos/subsys/win32k/objects/text.c +++ b/reactos/subsys/win32k/objects/text.c @@ -1,22 +1,28 @@ /* - * ReactOS W32 Subsystem - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team + * ReactOS W32 Subsystem + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Parts based on Wine code + * Copyright 1993 Alexandre Julliard + * 1997 Alex Korobka + * Copyright 2002,2003 Shachar Shemesh + * Copyright 2001 Huw D M Davies for CodeWeavers. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: text.c,v 1.81 2004/03/18 22:03:40 royce Exp $ */ +/* $Id: text.c,v 1.82 2004/03/23 00:18:54 gvg Exp $ */ #undef WIN32_LEAN_AND_MEAN @@ -63,6 +69,74 @@ static FAST_MUTEX FontListLock; static INT FontsLoaded = 0; /* number of all fonts loaded (including private fonts */ static BOOL RenderingEnabled = TRUE; +static PWCHAR ElfScripts[32] = { /* these are in the order of the fsCsb[0] bits */ + L"Western", /*00*/ + L"Central_European", + L"Cyrillic", + L"Greek", + L"Turkish", + L"Hebrew", + L"Arabic", + L"Baltic", + L"Vietnamese", /*08*/ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*15*/ + L"Thai", + L"Japanese", + L"CHINESE_GB2312", + L"Hangul", + L"CHINESE_BIG5", + L"Hangul(Johab)", + NULL, NULL, /*23*/ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + L"Symbol" /*31*/ +}; + +/* + * For NtGdiTranslateCharsetInfo + */ +#define FS(x) {{0,0,0,0},{0x1<<(x),0}} +#define MAXTCIINDEX 32 +static CHARSETINFO FontTci[MAXTCIINDEX] = { + /* ANSI */ + { ANSI_CHARSET, 1252, FS(0)}, + { EASTEUROPE_CHARSET, 1250, FS(1)}, + { RUSSIAN_CHARSET, 1251, FS(2)}, + { GREEK_CHARSET, 1253, FS(3)}, + { TURKISH_CHARSET, 1254, FS(4)}, + { HEBREW_CHARSET, 1255, FS(5)}, + { ARABIC_CHARSET, 1256, FS(6)}, + { BALTIC_CHARSET, 1257, FS(7)}, + { VIETNAMESE_CHARSET, 1258, FS(8)}, + /* reserved by ANSI */ + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + /* ANSI and OEM */ + { THAI_CHARSET, 874, FS(16)}, + { SHIFTJIS_CHARSET, 932, FS(17)}, + { GB2312_CHARSET, 936, FS(18)}, + { HANGEUL_CHARSET, 949, FS(19)}, + { CHINESEBIG5_CHARSET, 950, FS(20)}, + { JOHAB_CHARSET, 1361, FS(21)}, + /* reserved for alternate ANSI and OEM */ + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + { DEFAULT_CHARSET, 0, FS(0)}, + /* reserved for system */ + { DEFAULT_CHARSET, 0, FS(0)}, + { SYMBOL_CHARSET, CP_SYMBOL, FS(31)}, +}; + + BOOL FASTCALL IntIsFontRenderingEnabled(VOID) { @@ -546,25 +620,839 @@ NtGdiCreateScalableFontResource(DWORD Hidden, UNIMPLEMENTED; } -int -STDCALL -NtGdiEnumFontFamilies(HDC hDC, - LPCWSTR Family, - FONTENUMPROCW EnumFontFamProc, - LPARAM lParam) +/************************************************************************* + * TranslateCharsetInfo + * + * Fills a CHARSETINFO structure for a character set, code page, or + * font. This allows making the correspondance between different labelings + * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges) + * of the same encoding. + * + * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used, + * only one codepage should be set in *Src. + * + * RETURNS + * TRUE on success, FALSE on failure. + * + */ +static BOOLEAN STDCALL +IntTranslateCharsetInfo(PDWORD Src, /* [in] + if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE + if flags == TCI_SRCCHARSET: a character set value + if flags == TCI_SRCCODEPAGE: a code page value */ + LPCHARSETINFO Cs, /* [out] structure to receive charset information */ + DWORD Flags /* [in] determines interpretation of lpSrc */) { - UNIMPLEMENTED; + int Index = 0; + + switch (Flags) + { + case TCI_SRCFONTSIG: + while (0 == (*Src >> Index & 0x0001) && Index < MAXTCIINDEX) + { + Index++; + } + break; + case TCI_SRCCODEPAGE: + while ((UINT) (Src) != FontTci[Index].ciACP && Index < MAXTCIINDEX) + { + Index++; + } + break; + case TCI_SRCCHARSET: + while ((UINT) (Src) != FontTci[Index].ciCharset && Index < MAXTCIINDEX) + { + Index++; + } + break; + default: + return FALSE; + } + + if (MAXTCIINDEX <= Index || DEFAULT_CHARSET == FontTci[Index].ciCharset) + { + return FALSE; + } + + memcpy(Cs, &FontTci[Index], sizeof(CHARSETINFO)); + + return TRUE; } -int -STDCALL -NtGdiEnumFontFamiliesEx(HDC hDC, - LPLOGFONTW Logfont, - FONTENUMEXPROCW EnumFontFamExProc, - LPARAM lParam, - DWORD Flags) +BOOL STDCALL +NtGdiTranslateCharsetInfo(PDWORD Src, + LPCHARSETINFO UnsafeCs, + DWORD Flags) { - UNIMPLEMENTED; + CHARSETINFO Cs; + BOOLEAN Ret; + NTSTATUS Status; + + Ret = IntTranslateCharsetInfo(Src, &Cs, Flags); + if (Ret) + { + Status = MmCopyToCaller(UnsafeCs, &Cs, sizeof(CHARSETINFO)); + if (! NT_SUCCESS(Status)) + { + SetLastWin32Error(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + return (BOOL) Ret; +} + + +/************************************************************* + * IntGetOutlineTextMetrics + * + */ +static unsigned FASTCALL +IntGetOutlineTextMetrics(PFONTGDI FontGDI, UINT Size, + OUTLINETEXTMETRICW *Otm) +{ + unsigned Needed; + TT_OS2 *pOS2; + TT_HoriHeader *pHori; + TT_Postscript *pPost; + FT_Fixed XScale, YScale; + ANSI_STRING FamilyNameA, StyleNameA; + UNICODE_STRING FamilyNameW, StyleNameW, Regular; + char *Cp; + int Ascent, Descent; + TEXTMETRICW *TM; + + Needed = sizeof(OUTLINETEXTMETRICW); + + RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name); + RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE); + + RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name); + RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE); + + /* These names should be read from the TT name table */ + + /* length of otmpFamilyName */ + Needed += FamilyNameW.Length + sizeof(WCHAR); + + RtlInitUnicodeString(&Regular, L"regular"); + /* length of otmpFaceName */ + if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE)) + { + Needed += FamilyNameW.Length + sizeof(WCHAR); /* just the family name */ + } + else + { + Needed += FamilyNameW.Length + StyleNameW.Length + 2 * sizeof(WCHAR); /* family + " " + style */ + } + + /* length of otmpStyleName */ + Needed += StyleNameW.Length + sizeof(WCHAR); + + /* length of otmpFullName */ + Needed += FamilyNameW.Length + StyleNameW.Length + 2 * sizeof(WCHAR); + + if (Size < Needed) + { + RtlFreeUnicodeString(&FamilyNameW); + RtlFreeUnicodeString(&StyleNameW); + return Needed; + } + + XScale = FontGDI->face->size->metrics.x_scale; + YScale = FontGDI->face->size->metrics.y_scale; + + IntLockFreeType; + pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2); + if (NULL == pOS2) + { + IntUnLockFreeType; + DPRINT1("Can't find OS/2 table - not TT font?\n"); + RtlFreeUnicodeString(&StyleNameW); + RtlFreeUnicodeString(&FamilyNameW); + return 0; + } + + pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea); + if (NULL == pHori) + { + IntUnLockFreeType; + DPRINT1("Can't find HHEA table - not TT font?\n"); + RtlFreeUnicodeString(&StyleNameW); + RtlFreeUnicodeString(&FamilyNameW); + return 0; + } + + pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* we can live with this failing */ + IntUnLockFreeType; + + Otm->otmSize = Needed; + + if (0 == pOS2->usWinAscent + pOS2->usWinDescent) + { + Ascent = pHori->Ascender; + Descent = -pHori->Descender; + } + else + { + Ascent = pOS2->usWinAscent; + Descent = pOS2->usWinDescent; + } + + TM = &Otm->otmTextMetrics; + TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6; + TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6; + TM->tmInternalLeading = (FT_MulFix(Ascent + Descent + - FontGDI->face->units_per_EM, YScale) + 32) >> 6; + + TM->tmHeight = TM->tmAscent + TM->tmDescent; + + /* MSDN says: + * el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender))) + */ + TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap + - ((Ascent + Descent) + - (pHori->Ascender - pHori->Descender)), + YScale) + 32) >> 6); + + TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6; + if (0 == TM->tmAveCharWidth) + { + TM->tmAveCharWidth = 1; + } + TM->tmMaxCharWidth = (FT_MulFix(FontGDI->face->bbox.xMax - FontGDI->face->bbox.xMin, + XScale) + 32) >> 6; + TM->tmWeight = pOS2->usWeightClass; + TM->tmOverhang = 0; + TM->tmDigitizedAspectX = 300; + TM->tmDigitizedAspectY = 300; + TM->tmFirstChar = pOS2->usFirstCharIndex; + TM->tmLastChar = pOS2->usLastCharIndex; + TM->tmDefaultChar = pOS2->usDefaultChar; + TM->tmBreakChar = L'\0' != pOS2->usBreakChar ? pOS2->usBreakChar : ' '; + TM->tmItalic = (FontGDI->face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0; + TM->tmUnderlined = 0; /* entry in OS2 table */ + TM->tmStruckOut = 0; /* entry in OS2 table */ + + /* Yes TPMF_FIXED_PITCH is correct; braindead api */ + if (! FT_IS_FIXED_WIDTH(FontGDI->face)) + { + TM->tmPitchAndFamily = TMPF_FIXED_PITCH; + } + else + { + TM->tmPitchAndFamily = 0; + } + + switch (pOS2->panose[PAN_FAMILYTYPE_INDEX]) + { + case PAN_FAMILY_SCRIPT: + TM->tmPitchAndFamily |= FF_SCRIPT; + break; + case PAN_FAMILY_DECORATIVE: + case PAN_FAMILY_PICTORIAL: + TM->tmPitchAndFamily |= FF_DECORATIVE; + break; + case PAN_FAMILY_TEXT_DISPLAY: + if (0 == TM->tmPitchAndFamily) /* fixed */ + { + TM->tmPitchAndFamily = FF_MODERN; + } + else + { + switch (pOS2->panose[PAN_SERIFSTYLE_INDEX]) + { + case PAN_SERIF_NORMAL_SANS: + case PAN_SERIF_OBTUSE_SANS: + case PAN_SERIF_PERP_SANS: + TM->tmPitchAndFamily |= FF_SWISS; + break; + default: + TM->tmPitchAndFamily |= FF_ROMAN; + break; + } + } + break; + default: + TM->tmPitchAndFamily |= FF_DONTCARE; + } + + if (FT_IS_SCALABLE(FontGDI->face)) + { + TM->tmPitchAndFamily |= TMPF_VECTOR; + } + if (FT_IS_SFNT(FontGDI->face)) + { + TM->tmPitchAndFamily |= TMPF_TRUETYPE; + } + +#ifndef TODO + TM->tmCharSet = DEFAULT_CHARSET; +#endif + + Otm->otmFiller = 0; + memcpy(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT); + Otm->otmfsSelection = pOS2->fsSelection; + Otm->otmfsType = pOS2->fsType; + Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise; + Otm->otmsCharSlopeRun = pHori->caret_Slope_Run; + Otm->otmItalicAngle = 0; /* POST table */ + Otm->otmEMSquare = FontGDI->face->units_per_EM; + Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6; + Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6; + Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6; + Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6; + Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6; + Otm->otmrcFontBox.left = (FT_MulFix(FontGDI->face->bbox.xMin, XScale) + 32) >> 6; + Otm->otmrcFontBox.right = (FT_MulFix(FontGDI->face->bbox.xMax, XScale) + 32) >> 6; + Otm->otmrcFontBox.top = (FT_MulFix(FontGDI->face->bbox.yMax, YScale) + 32) >> 6; + Otm->otmrcFontBox.bottom = (FT_MulFix(FontGDI->face->bbox.yMin, YScale) + 32) >> 6; + Otm->otmMacAscent = 0; /* where do these come from ? */ + Otm->otmMacDescent = 0; + Otm->otmMacLineGap = 0; + Otm->otmusMinimumPPEM = 0; /* TT Header */ + Otm->otmptSubscriptSize.x = (FT_MulFix(pOS2->ySubscriptXSize, XScale) + 32) >> 6; + Otm->otmptSubscriptSize.y = (FT_MulFix(pOS2->ySubscriptYSize, YScale) + 32) >> 6; + Otm->otmptSubscriptOffset.x = (FT_MulFix(pOS2->ySubscriptXOffset, XScale) + 32) >> 6; + Otm->otmptSubscriptOffset.y = (FT_MulFix(pOS2->ySubscriptYOffset, YScale) + 32) >> 6; + Otm->otmptSuperscriptSize.x = (FT_MulFix(pOS2->ySuperscriptXSize, XScale) + 32) >> 6; + Otm->otmptSuperscriptSize.y = (FT_MulFix(pOS2->ySuperscriptYSize, YScale) + 32) >> 6; + Otm->otmptSuperscriptOffset.x = (FT_MulFix(pOS2->ySuperscriptXOffset, XScale) + 32) >> 6; + Otm->otmptSuperscriptOffset.y = (FT_MulFix(pOS2->ySuperscriptYOffset, YScale) + 32) >> 6; + Otm->otmsStrikeoutSize = (FT_MulFix(pOS2->yStrikeoutSize, YScale) + 32) >> 6; + Otm->otmsStrikeoutPosition = (FT_MulFix(pOS2->yStrikeoutPosition, YScale) + 32) >> 6; + if (NULL == pPost) + { + Otm->otmsUnderscoreSize = 0; + Otm->otmsUnderscorePosition = 0; + } + else + { + Otm->otmsUnderscoreSize = (FT_MulFix(pPost->underlineThickness, YScale) + 32) >> 6; + Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6; + } + + /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */ + Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW); + Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm); + wcscpy((WCHAR*) Cp, FamilyNameW.Buffer); + Cp += FamilyNameW.Length + sizeof(WCHAR); + Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm); + wcscpy((WCHAR*) Cp, StyleNameW.Buffer); + Cp += StyleNameW.Length + sizeof(WCHAR); + Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm); + wcscpy((WCHAR*) Cp, FamilyNameW.Buffer); + if (0 != RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE)) + { + wcscat((WCHAR*) Cp, L" "); + wcscat((WCHAR*) Cp, StyleNameW.Buffer); + Cp += FamilyNameW.Length + StyleNameW.Length + 2 * sizeof(WCHAR); + } + else + { + Cp += FamilyNameW.Length + sizeof(WCHAR); + } + Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm); + wcscpy((WCHAR*) Cp, FamilyNameW.Buffer); + wcscat((WCHAR*) Cp, L" "); + wcscat((WCHAR*) Cp, StyleNameW.Buffer); + + RtlFreeUnicodeString(&StyleNameW); + RtlFreeUnicodeString(&FamilyNameW); + + return Needed; +} + +static PFONTGDI FASTCALL +FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head) +{ + PLIST_ENTRY Entry; + PFONT_ENTRY CurrentEntry; + ANSI_STRING EntryFaceNameA; + UNICODE_STRING EntryFaceNameW; + PFONTGDI FontGDI; + + Entry = Head->Flink; + while (Entry != Head) + { + CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); + + if (NULL == (FontGDI = AccessInternalObject((ULONG) CurrentEntry->hFont))) + { + Entry = Entry->Flink; + continue; + } + RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name); + RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE); + if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length) + { + EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR); + EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0'; + } + + if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE)) + { + RtlFreeUnicodeString(&EntryFaceNameW); + return FontGDI; + } + + RtlFreeUnicodeString(&EntryFaceNameW); + Entry = Entry->Flink; + } + + return NULL; +} + +static PFONTGDI FASTCALL +FindFaceNameInLists(PUNICODE_STRING FaceName) +{ + PW32PROCESS Win32Process; + PFONTGDI Font; + + /* Search the process local list */ + Win32Process = PsGetWin32Process(); + IntLockProcessPrivateFonts(Win32Process); + Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead); + IntUnLockProcessPrivateFonts(Win32Process); + if (NULL != Font) + { + return Font; + } + + /* Search the global list */ + IntLockGlobalFonts; + Font = FindFaceNameInList(FaceName, &FontListHead); + IntUnLockGlobalFonts; + + return Font; +} + +static void FASTCALL +FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI) +{ + ANSI_STRING StyleA; + UNICODE_STRING StyleW; + TT_OS2 *pOS2; + FONTSIGNATURE fs; + DWORD fs_fsCsb0; + CHARSETINFO CharSetInfo; + unsigned i, Size; + OUTLINETEXTMETRICW *Otm; + LOGFONTW *Lf; + TEXTMETRICW *TM; + NEWTEXTMETRICW *Ntm; + + ZeroMemory(Info, sizeof(FONTFAMILYINFO)); + Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); + Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT); + if (NULL == Otm) + { + return; + } + IntGetOutlineTextMetrics(FontGDI, Size, Otm); + + Lf = &Info->EnumLogFontEx.elfLogFont; + TM = &Otm->otmTextMetrics; + + Lf->lfHeight = TM->tmHeight; + Lf->lfWidth = TM->tmAveCharWidth; + Lf->lfWeight = TM->tmWeight; + Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1; + Lf->lfCharSet = TM->tmCharSet; + Lf->lfOutPrecision = OUT_STROKE_PRECIS; + Lf->lfClipPrecision = CLIP_STROKE_PRECIS; + Lf->lfQuality = DRAFT_QUALITY; + + Ntm = &Info->NewTextMetricEx.ntmTm; + Ntm->tmHeight = TM->tmHeight; + Ntm->tmAscent = TM->tmAscent; + Ntm->tmDescent = TM->tmDescent; + Ntm->tmInternalLeading = TM->tmInternalLeading; + Ntm->tmExternalLeading = TM->tmExternalLeading; + Ntm->tmAveCharWidth = TM->tmAveCharWidth; + Ntm->tmMaxCharWidth = TM->tmMaxCharWidth; + Ntm->tmWeight = TM->tmWeight; + Ntm->tmOverhang = TM->tmOverhang; + Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX; + Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY; + Ntm->tmFirstChar = TM->tmFirstChar; + Ntm->tmLastChar = TM->tmLastChar; + Ntm->tmDefaultChar = TM->tmDefaultChar; + Ntm->tmBreakChar = TM->tmBreakChar; + Ntm->tmItalic = TM->tmItalic; + Ntm->tmUnderlined = TM->tmUnderlined; + Ntm->tmStruckOut = TM->tmStruckOut; + Ntm->tmPitchAndFamily = TM->tmPitchAndFamily; + Ntm->tmCharSet = TM->tmCharSet; + Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0; + if (550 < TM->tmWeight) + { + Ntm->ntmFlags |= NTM_BOLD; + } + if (0 == Ntm->ntmFlags) + { + Ntm->ntmFlags = NTM_REGULAR; + } + + Ntm->ntmSizeEM = Otm->otmEMSquare; + Ntm->ntmCellHeight = 0; + Ntm->ntmAvgWidth = 0; + + Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE) + ? TRUETYPE_FONTTYPE : 0); + if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR)) + { + Info->FontType |= RASTER_FONTTYPE; + } + + ExFreePool(Otm); + + wcsncpy(Info->EnumLogFontEx.elfLogFont.lfFaceName, FaceName, LF_FACESIZE); + wcsncpy(Info->EnumLogFontEx.elfFullName, FaceName, LF_FULLFACESIZE); + RtlInitAnsiString(&StyleA, FontGDI->face->style_name); + RtlAnsiStringToUnicodeString(&StyleW, &StyleA, TRUE); + wcsncpy(Info->EnumLogFontEx.elfStyle, StyleW.Buffer, LF_FACESIZE); + RtlFreeUnicodeString(&StyleW); + + Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET; + Info->EnumLogFontEx.elfScript[0] = L'\0'; + IntLockFreeType; + pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2); + IntUnLockFreeType; + if (NULL != pOS2) + { + Info->NewTextMetricEx.ntmFontSig.fsCsb[0] = pOS2->ulCodePageRange1; + Info->NewTextMetricEx.ntmFontSig.fsCsb[1] = pOS2->ulCodePageRange2; + Info->NewTextMetricEx.ntmFontSig.fsUsb[0] = pOS2->ulUnicodeRange1; + Info->NewTextMetricEx.ntmFontSig.fsUsb[1] = pOS2->ulUnicodeRange2; + Info->NewTextMetricEx.ntmFontSig.fsUsb[2] = pOS2->ulUnicodeRange3; + Info->NewTextMetricEx.ntmFontSig.fsUsb[3] = pOS2->ulUnicodeRange4; + + fs_fsCsb0 = pOS2->ulCodePageRange1; + if (0 == pOS2->version) + { + FT_UInt Dummy; + + if (FT_Get_First_Char(FontGDI->face, &Dummy) < 0x100) + { + fs_fsCsb0 |= 1; + } + else + { + fs_fsCsb0 |= 1L << 31; + } + } + if (0 == fs_fsCsb0) + { /* let's see if we can find any interesting cmaps */ + for (i = 0; i < FontGDI->face->num_charmaps; i++) + { + switch (FontGDI->face->charmaps[i]->encoding) + { + case ft_encoding_unicode: + case ft_encoding_apple_roman: + fs_fsCsb0 |= 1; + break; + case ft_encoding_symbol: + fs_fsCsb0 |= 1L << 31; + break; + default: + break; + } + } + } + + for(i = 0; i < 32; i++) + { + if (0 != (fs_fsCsb0 & (1L << i))) + { + fs.fsCsb[0] = 1L << i; + fs.fsCsb[1] = 0; + if (! IntTranslateCharsetInfo(fs.fsCsb, &CharSetInfo, TCI_SRCFONTSIG)) + { + CharSetInfo.ciCharset = DEFAULT_CHARSET; + } + if (31 == i) + { + CharSetInfo.ciCharset = SYMBOL_CHARSET; + } + if (DEFAULT_CHARSET != CharSetInfo.ciCharset) + { + Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset; + if (NULL != ElfScripts[i]) + { + wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]); + } + else + { + DPRINT1("Unknown elfscript for bit %d\n", i); + } + } + } + } + } +} + +static int FASTCALL +FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries) +{ + DWORD i; + UNICODE_STRING InfoFaceName; + + for (i = 0; i < InfoEntries; i++) + { + RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName); + if (0 == RtlCompareUnicodeString(&InfoFaceName, FaceName, TRUE)) + { + return i; + } + } + + return -1; +} + +static BOOLEAN FASTCALL +FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName, + PFONTFAMILYINFO Info, DWORD InfoEntries) +{ + UNICODE_STRING LogFontFaceName; + + RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName); + if (0 != LogFontFaceName.Length + && 0 != RtlCompareUnicodeString(&LogFontFaceName, FaceName, TRUE)) + { + return FALSE; + } + + return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0; +} + +static BOOLEAN FASTCALL +GetFontFamilyInfoForList(LPLOGFONTW LogFont, + PFONTFAMILYINFO Info, + DWORD *Count, + DWORD Size, + PLIST_ENTRY Head) +{ + PLIST_ENTRY Entry; + PFONT_ENTRY CurrentEntry; + ANSI_STRING EntryFaceNameA; + UNICODE_STRING EntryFaceNameW; + PFONTGDI FontGDI; + + Entry = Head->Flink; + while (Entry != Head) + { + CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); + + if (NULL == (FontGDI = AccessInternalObject((ULONG) CurrentEntry->hFont))) + { + Entry = Entry->Flink; + continue; + } + RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name); + RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE); + if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length) + { + EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR); + EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0'; + } + + if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size))) + { + if (*Count < Size) + { + FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI); + } + (*Count)++; + } + RtlFreeUnicodeString(&EntryFaceNameW); + Entry = Entry->Flink; + } + + return TRUE; +} + +typedef struct FontFamilyInfoCallbackContext +{ + LPLOGFONTW LogFont; + PFONTFAMILYINFO Info; + DWORD Count; + DWORD Size; +} FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT; + +static NTSTATUS STDCALL +FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType, + IN PVOID ValueData, IN ULONG ValueLength, + IN PVOID Context, IN PVOID EntryContext) +{ + PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext; + UNICODE_STRING RegistryName, RegistryValue; + int Existing; + PFONTGDI FontGDI; + + if (REG_SZ != ValueType) + { + return STATUS_SUCCESS; + } + InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context; + RtlInitUnicodeString(&RegistryName, ValueName); + + /* Do we need to include this font family? */ + if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info, + min(InfoContext->Count, InfoContext->Size))) + { + RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData); + Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info, + min(InfoContext->Count, InfoContext->Size)); + if (0 <= Existing) + { + /* We already have the information about the "real" font. Just copy it */ + if (InfoContext->Count < InfoContext->Size) + { + InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing]; + wcsncpy(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName, + RegistryName.Buffer, LF_FACESIZE); + } + InfoContext->Count++; + return STATUS_SUCCESS; + } + + /* Try to find information about the "real" font */ + FontGDI = FindFaceNameInLists(&RegistryValue); + if (NULL == FontGDI) + { + /* "Real" font not found, discard this registry entry */ + return STATUS_SUCCESS; + } + + /* Return info about the "real" font but with the name of the alias */ + if (InfoContext->Count < InfoContext->Size) + { + FontFamilyFillInfo(InfoContext->Info + InfoContext->Count, + RegistryName.Buffer, FontGDI); + } + InfoContext->Count++; + return STATUS_SUCCESS; + } + + return STATUS_SUCCESS; +} + +static BOOLEAN FASTCALL +GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont, + PFONTFAMILYINFO Info, + DWORD *Count, + DWORD Size) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + FONT_FAMILY_INFO_CALLBACK_CONTEXT Context; + NTSTATUS Status; + + /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\SysFontSubstitutes + The real work is done in the registry callback function */ + Context.LogFont = LogFont; + Context.Info = Info; + Context.Count = *Count; + Context.Size = Size; + + QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback; + QueryTable[0].Flags = 0; + QueryTable[0].Name = NULL; + QueryTable[0].EntryContext = NULL; + QueryTable[0].DefaultType = REG_NONE; + QueryTable[0].DefaultData = NULL; + QueryTable[0].DefaultLength = 0; + + QueryTable[1].QueryRoutine = NULL; + QueryTable[1].Name = NULL; + + Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, + L"SysFontSubstitutes", + QueryTable, + &Context, + NULL); + if (NT_SUCCESS(Status)) + { + *Count = Context.Count; + } + + return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status; +} + +int STDCALL +NtGdiGetFontFamilyInfo(HDC Dc, + LPLOGFONTW UnsafeLogFont, + PFONTFAMILYINFO UnsafeInfo, + DWORD Size) +{ + NTSTATUS Status; + LOGFONTW LogFont; + PFONTFAMILYINFO Info; + DWORD Count; + PW32PROCESS Win32Process; + + /* Make a safe copy */ + Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW)); + if (! NT_SUCCESS(Status)) + { + SetLastWin32Error(ERROR_INVALID_PARAMETER); + return -1; + } + + /* Allocate space for a safe copy */ + Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), TAG_GDITEXT); + if (NULL == Info) + { + SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY); + return -1; + } + + /* Enumerate font families in the global list */ + IntLockGlobalFonts; + Count = 0; + if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) ) + { + IntUnLockGlobalFonts; + ExFreePool(Info); + return -1; + } + IntUnLockGlobalFonts; + + /* Enumerate font families in the process local list */ + Win32Process = PsGetWin32Process(); + IntLockProcessPrivateFonts(Win32Process); + if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, + &Win32Process->PrivateFontListHead)) + { + IntUnLockProcessPrivateFonts(Win32Process); + ExFreePool(Info); + return -1; + } + IntUnLockProcessPrivateFonts(Win32Process); + + /* Enumerate font families in the registry */ + if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size)) + { + ExFreePool(Info); + return -1; + } + + /* Return data to caller */ + if (0 != Count) + { + Status = MmCopyToCaller(UnsafeInfo, Info, + (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO)); + if (! NT_SUCCESS(Status)) + { + ExFreePool(Info); + SetLastWin32Error(ERROR_INVALID_PARAMETER); + return -1; + } + } + + ExFreePool(Info); + + return Count; } int @@ -1689,15 +2577,6 @@ NtGdiTextOut( return NtGdiExtTextOut(hDC, XStart, YStart, 0, NULL, String, Count, NULL); } -UINT -STDCALL -NtGdiTranslateCharsetInfo(PDWORD Src, - LPCHARSETINFO CSI, - DWORD Flags) -{ - UNIMPLEMENTED; -} - NTSTATUS FASTCALL TextIntRealizeFont(HFONT FontHandle) {