mirror of
https://github.com/reactos/reactos.git
synced 2024-11-18 13:01:40 +00:00
b751c31c74
Add removed flags for batch signaling. This will allow syncing of changed Xfroms after batched drawing. Disable calls to kernel mode since the code is closely identical. Kernel calls are for init time when PDCATTR is normally zero. ReactOS seems to work better keeping this from NULL. While making code changes add Xform state flags from: https://www.reactos.org/archives/public/ros-diffs/2019-May/070693.html Test BOT results: https://reactos.org/testman/compare.php?ids=67251,67254 https://reactos.org/testman/compare.php?ids=67253,67255
2675 lines
68 KiB
C
2675 lines
68 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS system libraries
|
|
* FILE: win32ss/gdi/gdi32/objects/font.c
|
|
* PURPOSE:
|
|
* PROGRAMMER:
|
|
*
|
|
*/
|
|
|
|
#include <precomp.h>
|
|
|
|
#include <math.h>
|
|
#include <strsafe.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* Rounds a floating point number to integer. The world-to-viewport
|
|
* transformation process is done in floating point internally. This function
|
|
* is then used to round these coordinates to integer values.
|
|
*/
|
|
static __inline INT GDI_ROUND(FLOAT val)
|
|
{
|
|
return (int)floor(val + 0.5);
|
|
}
|
|
|
|
/*
|
|
* For TranslateCharsetInfo
|
|
*/
|
|
#define MAXTCIINDEX 32
|
|
static const CHARSETINFO FONT_tci[MAXTCIINDEX] =
|
|
{
|
|
/* ANSI */
|
|
{ ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
|
|
{ RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
|
|
{ GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
|
|
{ TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
|
|
{ HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
|
|
{ ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
|
|
{ BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
|
|
{ VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
|
|
/* reserved by ANSI */
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
/* ANSI and OEM */
|
|
{ THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
|
|
{ SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
|
|
{ GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
|
|
{ HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
|
|
{ CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
|
|
{ JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
|
|
/* reserved for alternate ANSI and OEM */
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
/* reserved for system */
|
|
{ DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
|
|
{ SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
|
|
};
|
|
|
|
#define INITIAL_FAMILY_COUNT 64
|
|
|
|
/***********************************************************************
|
|
* TEXTMETRIC conversion functions.
|
|
*/
|
|
VOID
|
|
FASTCALL
|
|
FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
|
|
{
|
|
ptmA->tmHeight = ptmW->tmHeight;
|
|
ptmA->tmAscent = ptmW->tmAscent;
|
|
ptmA->tmDescent = ptmW->tmDescent;
|
|
ptmA->tmInternalLeading = ptmW->tmInternalLeading;
|
|
ptmA->tmExternalLeading = ptmW->tmExternalLeading;
|
|
ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
|
|
ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
|
|
ptmA->tmWeight = ptmW->tmWeight;
|
|
ptmA->tmOverhang = ptmW->tmOverhang;
|
|
ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
|
|
ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
|
|
ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
|
|
if (ptmW->tmCharSet == SYMBOL_CHARSET)
|
|
{
|
|
ptmA->tmFirstChar = 0x1e;
|
|
ptmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
|
|
}
|
|
else
|
|
{
|
|
ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
|
|
ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
|
|
}
|
|
ptmA->tmDefaultChar = (CHAR)ptmW->tmDefaultChar;
|
|
ptmA->tmBreakChar = (CHAR)ptmW->tmBreakChar;
|
|
ptmA->tmItalic = ptmW->tmItalic;
|
|
ptmA->tmUnderlined = ptmW->tmUnderlined;
|
|
ptmA->tmStruckOut = ptmW->tmStruckOut;
|
|
ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
|
|
ptmA->tmCharSet = ptmW->tmCharSet;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* FONT_mbtowc
|
|
*
|
|
* Returns a Unicode translation of str using the charset of the
|
|
* currently selected font in hdc. If count is -1 then str is assumed
|
|
* to be '\0' terminated, otherwise it contains the number of bytes to
|
|
* convert. If plenW is non-NULL, on return it will point to the
|
|
* number of WCHARs that have been written. If pCP is non-NULL, on
|
|
* return it will point to the codepage used in the conversion. The
|
|
* caller should free the returned LPWSTR from the process heap
|
|
* itself.
|
|
*/
|
|
static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
|
|
{
|
|
UINT cp = GdiGetCodePage( hdc );
|
|
INT lenW;
|
|
LPWSTR strW;
|
|
|
|
if(count == -1) count = strlen(str);
|
|
lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
|
|
strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
|
|
if (!strW)
|
|
return NULL;
|
|
if(!MultiByteToWideChar(cp, 0, str, count, strW, lenW))
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, strW);
|
|
return NULL;
|
|
}
|
|
DPRINT("mapped %s -> %S\n", str, strW);
|
|
if(plenW) *plenW = lenW;
|
|
if(pCP) *pCP = cp;
|
|
return strW;
|
|
}
|
|
|
|
static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
|
|
{
|
|
INT i, count = lastChar - firstChar + 1;
|
|
UINT c;
|
|
LPSTR str;
|
|
|
|
if (count <= 0)
|
|
return NULL;
|
|
|
|
switch (GdiGetCodePage(hdc))
|
|
{
|
|
case 932:
|
|
case 936:
|
|
case 949:
|
|
case 950:
|
|
case 1361:
|
|
if (lastChar > 0xffff)
|
|
return NULL;
|
|
if ((firstChar ^ lastChar) > 0xff)
|
|
return NULL;
|
|
break;
|
|
default:
|
|
if (lastChar > 0xff)
|
|
return NULL;
|
|
break;
|
|
}
|
|
|
|
str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
|
|
if (str == NULL)
|
|
return NULL;
|
|
|
|
for(i = 0, c = firstChar; c <= lastChar; i++, c++)
|
|
{
|
|
if (c > 0xff)
|
|
str[i++] = (BYTE)(c >> 8);
|
|
str[i] = (BYTE)c;
|
|
}
|
|
str[i] = '\0';
|
|
|
|
*pByteLen = i;
|
|
|
|
return str;
|
|
}
|
|
|
|
VOID FASTCALL
|
|
NewTextMetricW2A(NEWTEXTMETRICA *tma, NEWTEXTMETRICW *tmw)
|
|
{
|
|
FONT_TextMetricWToA((TEXTMETRICW *) tmw, (TEXTMETRICA *) tma);
|
|
tma->ntmFlags = tmw->ntmFlags;
|
|
tma->ntmSizeEM = tmw->ntmSizeEM;
|
|
tma->ntmCellHeight = tmw->ntmCellHeight;
|
|
tma->ntmAvgWidth = tmw->ntmAvgWidth;
|
|
}
|
|
|
|
VOID FASTCALL
|
|
NewTextMetricExW2A(NEWTEXTMETRICEXA *tma, NEWTEXTMETRICEXW *tmw)
|
|
{
|
|
NewTextMetricW2A(&tma->ntmTm, &tmw->ntmTm);
|
|
tma->ntmFontSig = tmw->ntmFontSig;
|
|
}
|
|
|
|
// IntFontFamilyCompareEx's flags
|
|
#define IFFCX_CHARSET 1
|
|
#define IFFCX_STYLE 2
|
|
|
|
FORCEINLINE int FASTCALL
|
|
IntFontFamilyCompareEx(const FONTFAMILYINFO *ffi1,
|
|
const FONTFAMILYINFO *ffi2, DWORD dwCompareFlags)
|
|
{
|
|
const LOGFONTW *plf1 = &ffi1->EnumLogFontEx.elfLogFont;
|
|
const LOGFONTW *plf2 = &ffi2->EnumLogFontEx.elfLogFont;
|
|
ULONG WeightDiff1, WeightDiff2;
|
|
int cmp = _wcsicmp(plf1->lfFaceName, plf2->lfFaceName);
|
|
if (cmp)
|
|
return cmp;
|
|
if (dwCompareFlags & IFFCX_CHARSET)
|
|
{
|
|
if (plf1->lfCharSet < plf2->lfCharSet)
|
|
return -1;
|
|
if (plf1->lfCharSet > plf2->lfCharSet)
|
|
return 1;
|
|
}
|
|
if (dwCompareFlags & IFFCX_STYLE)
|
|
{
|
|
WeightDiff1 = labs(plf1->lfWeight - FW_NORMAL);
|
|
WeightDiff2 = labs(plf2->lfWeight - FW_NORMAL);
|
|
if (WeightDiff1 < WeightDiff2)
|
|
return -1;
|
|
if (WeightDiff1 > WeightDiff2)
|
|
return 1;
|
|
if (plf1->lfItalic < plf2->lfItalic)
|
|
return -1;
|
|
if (plf1->lfItalic > plf2->lfItalic)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int __cdecl
|
|
IntFontFamilyCompare(const void *ffi1, const void *ffi2)
|
|
{
|
|
return IntFontFamilyCompareEx(ffi1, ffi2, IFFCX_STYLE | IFFCX_CHARSET);
|
|
}
|
|
|
|
// IntEnumFontFamilies' flags:
|
|
#define IEFF_UNICODE 1
|
|
#define IEFF_EXTENDED 2
|
|
|
|
int FASTCALL
|
|
IntFontFamilyListUnique(FONTFAMILYINFO *InfoList, INT nCount,
|
|
const LOGFONTW *plf, DWORD dwFlags)
|
|
{
|
|
FONTFAMILYINFO *first, *last, *result;
|
|
DWORD dwCompareFlags = 0;
|
|
|
|
if (plf->lfFaceName[0])
|
|
dwCompareFlags |= IFFCX_STYLE;
|
|
|
|
if ((dwFlags & IEFF_EXTENDED) && plf->lfCharSet == DEFAULT_CHARSET)
|
|
dwCompareFlags |= IFFCX_CHARSET;
|
|
|
|
first = InfoList;
|
|
last = &InfoList[nCount];
|
|
|
|
/* std::unique(first, last, IntFontFamilyCompareEx); */
|
|
if (first == last)
|
|
return 0;
|
|
|
|
result = first;
|
|
while (++first != last)
|
|
{
|
|
if (IntFontFamilyCompareEx(result, first, dwCompareFlags) != 0)
|
|
{
|
|
*(++result) = *first;
|
|
}
|
|
}
|
|
nCount = (int)(++result - InfoList);
|
|
|
|
return nCount;
|
|
}
|
|
|
|
static int FASTCALL
|
|
IntEnumFontFamilies(HDC Dc, const LOGFONTW *LogFont, PVOID EnumProc, LPARAM lParam,
|
|
DWORD dwFlags)
|
|
{
|
|
int FontFamilyCount;
|
|
PFONTFAMILYINFO Info;
|
|
int Ret = 1;
|
|
int i;
|
|
ENUMLOGFONTEXA EnumLogFontExA;
|
|
NEWTEXTMETRICEXA NewTextMetricExA;
|
|
LOGFONTW lfW;
|
|
LONG InfoCount;
|
|
ULONG DataSize;
|
|
NTSTATUS Status;
|
|
|
|
DataSize = INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO);
|
|
Info = RtlAllocateHeap(GetProcessHeap(), 0, DataSize);
|
|
if (Info == NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/* Initialize the LOGFONT structure */
|
|
ZeroMemory(&lfW, sizeof(lfW));
|
|
if (!LogFont)
|
|
{
|
|
lfW.lfCharSet = DEFAULT_CHARSET;
|
|
}
|
|
else
|
|
{
|
|
lfW.lfCharSet = LogFont->lfCharSet;
|
|
lfW.lfPitchAndFamily = LogFont->lfPitchAndFamily;
|
|
StringCbCopyW(lfW.lfFaceName, sizeof(lfW.lfFaceName), LogFont->lfFaceName);
|
|
}
|
|
|
|
/* Retrieve the font information */
|
|
InfoCount = INITIAL_FAMILY_COUNT;
|
|
FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, &lfW, Info, &InfoCount);
|
|
if (FontFamilyCount < 0)
|
|
{
|
|
RtlFreeHeap(GetProcessHeap(), 0, Info);
|
|
return 1;
|
|
}
|
|
|
|
/* Resize the buffer if the buffer is too small */
|
|
if (INITIAL_FAMILY_COUNT < InfoCount)
|
|
{
|
|
RtlFreeHeap(GetProcessHeap(), 0, Info);
|
|
|
|
Status = RtlULongMult(InfoCount, sizeof(FONTFAMILYINFO), &DataSize);
|
|
if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
|
|
{
|
|
DPRINT1("Overflowed.\n");
|
|
return 1;
|
|
}
|
|
Info = RtlAllocateHeap(GetProcessHeap(), 0, DataSize);
|
|
if (Info == NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, &lfW, Info, &InfoCount);
|
|
if (FontFamilyCount < 0 || FontFamilyCount < InfoCount)
|
|
{
|
|
RtlFreeHeap(GetProcessHeap(), 0, Info);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* Sort and remove redundant information */
|
|
qsort(Info, FontFamilyCount, sizeof(*Info), IntFontFamilyCompare);
|
|
FontFamilyCount = IntFontFamilyListUnique(Info, FontFamilyCount, &lfW, dwFlags);
|
|
|
|
/* call the callback */
|
|
for (i = 0; i < FontFamilyCount; i++)
|
|
{
|
|
if (dwFlags & IEFF_UNICODE)
|
|
{
|
|
Ret = ((FONTENUMPROCW) EnumProc)(
|
|
(VOID*)&Info[i].EnumLogFontEx,
|
|
(VOID*)&Info[i].NewTextMetricEx,
|
|
Info[i].FontType, lParam);
|
|
}
|
|
else
|
|
{
|
|
// Could use EnumLogFontExW2A here?
|
|
LogFontW2A(&EnumLogFontExA.elfLogFont, &Info[i].EnumLogFontEx.elfLogFont);
|
|
WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfFullName, -1,
|
|
(LPSTR)EnumLogFontExA.elfFullName, LF_FULLFACESIZE, NULL, NULL);
|
|
WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfStyle, -1,
|
|
(LPSTR)EnumLogFontExA.elfStyle, LF_FACESIZE, NULL, NULL);
|
|
WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfScript, -1,
|
|
(LPSTR)EnumLogFontExA.elfScript, LF_FACESIZE, NULL, NULL);
|
|
NewTextMetricExW2A(&NewTextMetricExA,
|
|
&Info[i].NewTextMetricEx);
|
|
Ret = ((FONTENUMPROCA) EnumProc)(
|
|
(VOID*)&EnumLogFontExA,
|
|
(VOID*)&NewTextMetricExA,
|
|
Info[i].FontType, lParam);
|
|
}
|
|
|
|
if(Ret == 0)
|
|
break;
|
|
}
|
|
|
|
RtlFreeHeap(GetProcessHeap(), 0, Info);
|
|
|
|
return Ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
int WINAPI
|
|
EnumFontFamiliesExW(HDC hdc, LPLOGFONTW lpLogfont, FONTENUMPROCW lpEnumFontFamExProc,
|
|
LPARAM lParam, DWORD dwFlags)
|
|
{
|
|
if (lpLogfont)
|
|
{
|
|
DPRINT("EnumFontFamiliesExW(%p, %p(%S, %u, %u), %p, %p, 0x%08lX)\n",
|
|
hdc, lpLogfont, lpLogfont->lfFaceName, lpLogfont->lfCharSet,
|
|
lpLogfont->lfPitchAndFamily, lpEnumFontFamExProc, lParam, dwFlags);
|
|
}
|
|
else
|
|
{
|
|
DPRINT("EnumFontFamiliesExW(%p, NULL, %p, %p, 0x%08lX)\n",
|
|
hdc, lpEnumFontFamExProc, lParam, dwFlags);
|
|
}
|
|
return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam,
|
|
IEFF_UNICODE | IEFF_EXTENDED);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
int WINAPI
|
|
EnumFontFamiliesW(HDC hdc, LPCWSTR lpszFamily, FONTENUMPROCW lpEnumFontFamProc,
|
|
LPARAM lParam)
|
|
{
|
|
LOGFONTW LogFont;
|
|
|
|
DPRINT("EnumFontFamiliesW(%p, %S, %p, %p)\n",
|
|
hdc, lpszFamily, lpEnumFontFamProc, lParam);
|
|
|
|
ZeroMemory(&LogFont, sizeof(LOGFONTW));
|
|
LogFont.lfCharSet = DEFAULT_CHARSET;
|
|
if (NULL != lpszFamily)
|
|
{
|
|
if (!*lpszFamily) return 1;
|
|
lstrcpynW(LogFont.lfFaceName, lpszFamily, LF_FACESIZE);
|
|
}
|
|
|
|
return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, IEFF_UNICODE);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
int WINAPI
|
|
EnumFontFamiliesExA (HDC hdc, LPLOGFONTA lpLogfont, FONTENUMPROCA lpEnumFontFamExProc,
|
|
LPARAM lParam, DWORD dwFlags)
|
|
{
|
|
LOGFONTW LogFontW, *pLogFontW;
|
|
|
|
if (lpLogfont)
|
|
{
|
|
DPRINT("EnumFontFamiliesExA(%p, %p(%s, %u, %u), %p, %p, 0x%08lX)\n",
|
|
hdc, lpLogfont, lpLogfont->lfFaceName, lpLogfont->lfCharSet,
|
|
lpLogfont->lfPitchAndFamily, lpEnumFontFamExProc, lParam, dwFlags);
|
|
}
|
|
else
|
|
{
|
|
DPRINT("EnumFontFamiliesExA(%p, NULL, %p, %p, 0x%08lX)\n",
|
|
hdc, lpEnumFontFamExProc, lParam, dwFlags);
|
|
}
|
|
|
|
if (lpLogfont)
|
|
{
|
|
LogFontA2W(&LogFontW,lpLogfont);
|
|
pLogFontW = &LogFontW;
|
|
}
|
|
else pLogFontW = NULL;
|
|
|
|
/* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */
|
|
return IntEnumFontFamilies(hdc, pLogFontW, lpEnumFontFamExProc, lParam, IEFF_EXTENDED);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
int WINAPI
|
|
EnumFontFamiliesA(HDC hdc, LPCSTR lpszFamily, FONTENUMPROCA lpEnumFontFamProc,
|
|
LPARAM lParam)
|
|
{
|
|
LOGFONTW LogFont;
|
|
|
|
DPRINT("EnumFontFamiliesA(%p, %s, %p, %p)\n",
|
|
hdc, lpszFamily, lpEnumFontFamProc, lParam);
|
|
|
|
ZeroMemory(&LogFont, sizeof(LOGFONTW));
|
|
LogFont.lfCharSet = DEFAULT_CHARSET;
|
|
if (NULL != lpszFamily)
|
|
{
|
|
if (!*lpszFamily) return 1;
|
|
MultiByteToWideChar(CP_THREAD_ACP, 0, lpszFamily, -1, LogFont.lfFaceName, LF_FACESIZE);
|
|
}
|
|
|
|
return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, 0);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
GetCharacterPlacementA(
|
|
HDC hdc,
|
|
LPCSTR lpString,
|
|
INT uCount,
|
|
INT nMaxExtent,
|
|
GCP_RESULTSA *lpResults,
|
|
DWORD dwFlags)
|
|
{
|
|
WCHAR *lpStringW;
|
|
INT uCountW;
|
|
GCP_RESULTSW resultsW;
|
|
DWORD ret;
|
|
UINT font_cp;
|
|
|
|
if ( !lpString || uCount <= 0 || !lpResults || (nMaxExtent < 0 && nMaxExtent != -1 ) )
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
/* TRACE("%s, %d, %d, 0x%08x\n",
|
|
debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
|
|
*/
|
|
/* both structs are equal in size */
|
|
memcpy(&resultsW, lpResults, sizeof(resultsW));
|
|
|
|
lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
|
|
if (lpStringW == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
if(lpResults->lpOutString)
|
|
{
|
|
resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
|
|
if (resultsW.lpOutString == NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, lpStringW);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
|
|
|
|
lpResults->nGlyphs = resultsW.nGlyphs;
|
|
lpResults->nMaxFit = resultsW.nMaxFit;
|
|
|
|
if(lpResults->lpOutString)
|
|
{
|
|
WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
|
|
lpResults->lpOutString, uCount, NULL, NULL );
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, lpStringW);
|
|
HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
GetCharacterPlacementW(
|
|
HDC hdc,
|
|
LPCWSTR lpString,
|
|
INT uCount,
|
|
INT nMaxExtent,
|
|
GCP_RESULTSW *lpResults,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
DWORD ret=0;
|
|
SIZE size;
|
|
UINT i, nSet;
|
|
DPRINT("GetCharacterPlacementW\n");
|
|
|
|
if (dwFlags&(~GCP_REORDER)) DPRINT("flags 0x%08lx ignored\n", dwFlags);
|
|
if (lpResults->lpClass) DPRINT("classes not implemented\n");
|
|
|
|
nSet = (UINT)uCount;
|
|
if (nSet > lpResults->nGlyphs)
|
|
nSet = lpResults->nGlyphs;
|
|
|
|
/* return number of initialized fields */
|
|
lpResults->nGlyphs = nSet;
|
|
|
|
if (dwFlags & GCP_REORDER)
|
|
{
|
|
if (LoadLPK(LPK_GCP))
|
|
return LpkGetCharacterPlacement(hdc, lpString, uCount, nMaxExtent, lpResults, dwFlags, 0);
|
|
}
|
|
|
|
/* Treat the case where no special handling was requested in a fastpath way */
|
|
/* copy will do if the GCP_REORDER flag is not set */
|
|
if (lpResults->lpOutString)
|
|
lstrcpynW( lpResults->lpOutString, lpString, nSet );
|
|
|
|
if (lpResults->lpOrder)
|
|
{
|
|
for (i = 0; i < nSet; i++)
|
|
lpResults->lpOrder[i] = i;
|
|
}
|
|
|
|
/* FIXME: Will use the placement chars */
|
|
if (lpResults->lpDx)
|
|
{
|
|
int c;
|
|
for (i = 0; i < nSet; i++)
|
|
{
|
|
if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
|
|
lpResults->lpDx[i]= c;
|
|
}
|
|
}
|
|
|
|
if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
|
|
{
|
|
int pos = 0;
|
|
|
|
lpResults->lpCaretPos[0] = 0;
|
|
for (i = 1; i < nSet; i++)
|
|
if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
|
|
lpResults->lpCaretPos[i] = (pos += size.cx);
|
|
}
|
|
|
|
if (lpResults->lpGlyphs)
|
|
NtGdiGetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
|
|
|
|
if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
|
|
ret = MAKELONG(size.cx, size.cy);
|
|
|
|
return ret;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
NewGetCharacterPlacementW(
|
|
HDC hdc,
|
|
LPCWSTR lpString,
|
|
INT uCount,
|
|
INT nMaxExtent,
|
|
GCP_RESULTSW *lpResults,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
ULONG nSet;
|
|
SIZE Size = {0,0};
|
|
|
|
if ( !lpString || uCount <= 0 || (nMaxExtent < 0 && nMaxExtent != -1 ) )
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if ( !lpResults )
|
|
{
|
|
if ( GetTextExtentPointW(hdc, lpString, uCount, &Size) )
|
|
{
|
|
return MAKELONG(Size.cx, Size.cy);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
nSet = uCount;
|
|
if ( nSet > lpResults->nGlyphs )
|
|
nSet = lpResults->nGlyphs;
|
|
|
|
return NtGdiGetCharacterPlacementW( hdc,
|
|
(LPWSTR)lpString,
|
|
nSet,
|
|
nMaxExtent,
|
|
lpResults,
|
|
dwFlags);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetCharABCWidthsFloatW(HDC hdc,
|
|
UINT FirstChar,
|
|
UINT LastChar,
|
|
LPABCFLOAT abcF)
|
|
{
|
|
DPRINT("GetCharABCWidthsFloatW\n");
|
|
if ((!abcF) || (FirstChar > LastChar))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
return NtGdiGetCharABCWidthsW( hdc,
|
|
FirstChar,
|
|
(ULONG)(LastChar - FirstChar + 1),
|
|
(PWCHAR) NULL,
|
|
0,
|
|
(PVOID)abcF);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetCharWidthFloatW(HDC hdc,
|
|
UINT iFirstChar,
|
|
UINT iLastChar,
|
|
PFLOAT pxBuffer)
|
|
{
|
|
DPRINT("GetCharWidthsFloatW\n");
|
|
if ((!pxBuffer) || (iFirstChar > iLastChar))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
return NtGdiGetCharWidthW( hdc,
|
|
iFirstChar,
|
|
(ULONG)(iLastChar - iFirstChar + 1),
|
|
(PWCHAR) NULL,
|
|
0,
|
|
(PVOID) pxBuffer);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetCharWidthW(HDC hdc,
|
|
UINT iFirstChar,
|
|
UINT iLastChar,
|
|
LPINT lpBuffer)
|
|
{
|
|
DPRINT("GetCharWidthsW\n");
|
|
if ((!lpBuffer) || (iFirstChar > iLastChar))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
return NtGdiGetCharWidthW( hdc,
|
|
iFirstChar,
|
|
(ULONG)(iLastChar - iFirstChar + 1),
|
|
(PWCHAR) NULL,
|
|
GCW_NOFLOAT,
|
|
(PVOID) lpBuffer);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetCharWidth32W(HDC hdc,
|
|
UINT iFirstChar,
|
|
UINT iLastChar,
|
|
LPINT lpBuffer)
|
|
{
|
|
DPRINT("GetCharWidths32W\n");
|
|
if ((!lpBuffer) || (iFirstChar > iLastChar))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
return NtGdiGetCharWidthW( hdc,
|
|
iFirstChar,
|
|
(ULONG)(iLastChar - iFirstChar + 1),
|
|
(PWCHAR) NULL,
|
|
GCW_NOFLOAT|GCW_WIN32,
|
|
(PVOID) lpBuffer);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetCharABCWidthsW(HDC hdc,
|
|
UINT FirstChar,
|
|
UINT LastChar,
|
|
LPABC lpabc)
|
|
{
|
|
DPRINT("GetCharABCWidthsW\n");
|
|
if ((!lpabc) || (FirstChar > LastChar))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
return NtGdiGetCharABCWidthsW( hdc,
|
|
FirstChar,
|
|
(ULONG)(LastChar - FirstChar + 1),
|
|
(PWCHAR) NULL,
|
|
GCABCW_NOFLOAT,
|
|
(PVOID)lpabc);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetCharWidthA(
|
|
HDC hdc,
|
|
UINT iFirstChar,
|
|
UINT iLastChar,
|
|
LPINT lpBuffer
|
|
)
|
|
{
|
|
INT wlen, count = 0;
|
|
LPSTR str;
|
|
LPWSTR wstr;
|
|
BOOL ret = TRUE;
|
|
|
|
DPRINT("GetCharWidthsA\n");
|
|
|
|
str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count);
|
|
if (!str)
|
|
return FALSE;
|
|
|
|
wstr = FONT_mbtowc(hdc, str, count+1, &wlen, NULL);
|
|
if (!wstr)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, str);
|
|
return FALSE;
|
|
}
|
|
|
|
ret = NtGdiGetCharWidthW( hdc,
|
|
wstr[0],
|
|
(ULONG) count,
|
|
(PWCHAR) wstr,
|
|
GCW_NOFLOAT,
|
|
(PVOID) lpBuffer);
|
|
|
|
HeapFree(GetProcessHeap(), 0, str);
|
|
HeapFree(GetProcessHeap(), 0, wstr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetCharWidth32A(
|
|
HDC hdc,
|
|
UINT iFirstChar,
|
|
UINT iLastChar,
|
|
LPINT lpBuffer
|
|
)
|
|
{
|
|
INT wlen, count = 0;
|
|
LPSTR str;
|
|
LPWSTR wstr;
|
|
BOOL ret = TRUE;
|
|
|
|
DPRINT("GetCharWidths32A\n");
|
|
|
|
str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count);
|
|
if (!str)
|
|
return FALSE;
|
|
|
|
wstr = FONT_mbtowc(hdc, str, count+1, &wlen, NULL);
|
|
if (!wstr)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, str);
|
|
return FALSE;
|
|
}
|
|
|
|
ret = NtGdiGetCharWidthW( hdc,
|
|
wstr[0],
|
|
(ULONG) count,
|
|
(PWCHAR) wstr,
|
|
GCW_NOFLOAT|GCW_WIN32,
|
|
(PVOID) lpBuffer);
|
|
|
|
HeapFree(GetProcessHeap(), 0, str);
|
|
HeapFree(GetProcessHeap(), 0, wstr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
APIENTRY
|
|
GetCharWidthFloatA(
|
|
HDC hdc,
|
|
UINT iFirstChar,
|
|
UINT iLastChar,
|
|
PFLOAT pxBuffer
|
|
)
|
|
{
|
|
INT wlen, count = 0;
|
|
LPSTR str;
|
|
LPWSTR wstr;
|
|
BOOL ret = TRUE;
|
|
|
|
DPRINT("GetCharWidthsFloatA\n");
|
|
|
|
str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count);
|
|
if (!str)
|
|
return FALSE;
|
|
|
|
wstr = FONT_mbtowc(hdc, str, count+1, &wlen, NULL);
|
|
if (!wstr)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, str);
|
|
return FALSE;
|
|
}
|
|
ret = NtGdiGetCharWidthW( hdc, wstr[0], (ULONG) count, (PWCHAR) wstr, 0, (PVOID) pxBuffer);
|
|
|
|
HeapFree(GetProcessHeap(), 0, str);
|
|
HeapFree(GetProcessHeap(), 0, wstr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
APIENTRY
|
|
GetCharABCWidthsA(
|
|
HDC hdc,
|
|
UINT iFirstChar,
|
|
UINT iLastChar,
|
|
LPABC lpabc
|
|
)
|
|
{
|
|
INT wlen, count = 0;
|
|
LPSTR str;
|
|
LPWSTR wstr;
|
|
BOOL ret = TRUE;
|
|
|
|
DPRINT("GetCharABCWidthsA\n");
|
|
|
|
str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count);
|
|
if (!str)
|
|
return FALSE;
|
|
|
|
wstr = FONT_mbtowc(hdc, str, count+1, &wlen, NULL);
|
|
if (!wstr)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, str);
|
|
return FALSE;
|
|
}
|
|
|
|
ret = NtGdiGetCharABCWidthsW( hdc,
|
|
wstr[0],
|
|
wlen - 1,
|
|
(PWCHAR)wstr,
|
|
GCABCW_NOFLOAT,
|
|
(PVOID)lpabc);
|
|
|
|
HeapFree(GetProcessHeap(), 0, str);
|
|
HeapFree(GetProcessHeap(), 0, wstr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
APIENTRY
|
|
GetCharABCWidthsFloatA(
|
|
HDC hdc,
|
|
UINT iFirstChar,
|
|
UINT iLastChar,
|
|
LPABCFLOAT lpABCF
|
|
)
|
|
{
|
|
INT wlen, count = 0;
|
|
LPSTR str;
|
|
LPWSTR wstr;
|
|
BOOL ret = TRUE;
|
|
|
|
DPRINT("GetCharABCWidthsFloatA\n");
|
|
|
|
str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count);
|
|
if (!str)
|
|
return FALSE;
|
|
|
|
wstr = FONT_mbtowc( hdc, str, count+1, &wlen, NULL );
|
|
if (!wstr)
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, str );
|
|
return FALSE;
|
|
}
|
|
ret = NtGdiGetCharABCWidthsW( hdc,wstr[0],(ULONG)count, (PWCHAR)wstr, 0, (PVOID)lpABCF);
|
|
|
|
HeapFree( GetProcessHeap(), 0, str );
|
|
HeapFree( GetProcessHeap(), 0, wstr );
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetCharABCWidthsI(HDC hdc,
|
|
UINT giFirst,
|
|
UINT cgi,
|
|
LPWORD pgi,
|
|
LPABC lpabc)
|
|
{
|
|
DPRINT("GetCharABCWidthsI\n");
|
|
return NtGdiGetCharABCWidthsW( hdc,
|
|
giFirst,
|
|
(ULONG) cgi,
|
|
(PWCHAR) pgi,
|
|
GCABCW_NOFLOAT|GCABCW_INDICES,
|
|
(PVOID)lpabc);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetCharWidthI(HDC hdc,
|
|
UINT giFirst,
|
|
UINT cgi,
|
|
LPWORD pgi,
|
|
LPINT lpBuffer
|
|
)
|
|
{
|
|
DPRINT("GetCharWidthsI\n");
|
|
if (!lpBuffer || (!pgi && (giFirst == MAXUSHORT))) // Cannot be at max.
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
if (!cgi) return TRUE;
|
|
return NtGdiGetCharWidthW( hdc,
|
|
giFirst,
|
|
cgi,
|
|
(PWCHAR) pgi,
|
|
GCW_INDICES|GCW_NOFLOAT|GCW_WIN32,
|
|
(PVOID) lpBuffer );
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
GetFontLanguageInfo(
|
|
HDC hDc
|
|
)
|
|
{
|
|
DWORD Gcp = 0, Ret = 0;
|
|
if (gbLpk)
|
|
{
|
|
Ret = NtGdiGetTextCharsetInfo(hDc, NULL, 0);
|
|
if ((Ret == ARABIC_CHARSET) || (Ret == HEBREW_CHARSET))
|
|
Ret = (GCP_KASHIDA|GCP_DIACRITIC|GCP_LIGATE|GCP_GLYPHSHAPE|GCP_REORDER);
|
|
}
|
|
Gcp = GetDCDWord(hDc, GdiGetFontLanguageInfo, GCP_ERROR);
|
|
if ( Gcp == GCP_ERROR)
|
|
return Gcp;
|
|
else
|
|
Ret = Gcp | Ret;
|
|
return Ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
GetGlyphIndicesA(
|
|
HDC hdc,
|
|
LPCSTR lpstr,
|
|
INT count,
|
|
LPWORD pgi,
|
|
DWORD flags
|
|
)
|
|
{
|
|
DWORD Ret;
|
|
WCHAR *lpstrW;
|
|
INT countW;
|
|
|
|
lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
|
|
|
|
if (lpstrW == NULL)
|
|
return GDI_ERROR;
|
|
|
|
Ret = NtGdiGetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
|
|
HeapFree(GetProcessHeap(), 0, lpstrW);
|
|
return Ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
GetGlyphOutlineA(
|
|
HDC hdc,
|
|
UINT uChar,
|
|
UINT uFormat,
|
|
LPGLYPHMETRICS lpgm,
|
|
DWORD cbBuffer,
|
|
LPVOID lpvBuffer,
|
|
CONST MAT2 *lpmat2
|
|
)
|
|
{
|
|
|
|
LPWSTR p = NULL;
|
|
DWORD ret;
|
|
UINT c;
|
|
DPRINT("GetGlyphOutlineA uChar %x\n", uChar);
|
|
if (!lpgm || !lpmat2) return GDI_ERROR;
|
|
if(!(uFormat & GGO_GLYPH_INDEX))
|
|
{
|
|
int len;
|
|
char mbchs[2];
|
|
if(uChar > 0xff) /* but, 2 bytes character only */
|
|
{
|
|
len = 2;
|
|
mbchs[0] = (uChar & 0xff00) >> 8;
|
|
mbchs[1] = (uChar & 0xff);
|
|
}
|
|
else
|
|
{
|
|
len = 1;
|
|
mbchs[0] = (uChar & 0xff);
|
|
}
|
|
p = FONT_mbtowc(hdc, mbchs, len, NULL, NULL);
|
|
if(!p)
|
|
return GDI_ERROR;
|
|
c = p[0];
|
|
}
|
|
else
|
|
c = uChar;
|
|
ret = NtGdiGetGlyphOutline(hdc, c, uFormat, lpgm, cbBuffer, lpvBuffer, (CONST LPMAT2)lpmat2, TRUE);
|
|
HeapFree(GetProcessHeap(), 0, p);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
GetGlyphOutlineW(
|
|
HDC hdc,
|
|
UINT uChar,
|
|
UINT uFormat,
|
|
LPGLYPHMETRICS lpgm,
|
|
DWORD cbBuffer,
|
|
LPVOID lpvBuffer,
|
|
CONST MAT2 *lpmat2
|
|
)
|
|
{
|
|
DPRINT("GetGlyphOutlineW uChar %x\n", uChar);
|
|
if (!lpgm || !lpmat2) return GDI_ERROR;
|
|
if (!lpvBuffer) cbBuffer = 0;
|
|
return NtGdiGetGlyphOutline ( hdc, uChar, uFormat, lpgm, cbBuffer, lpvBuffer, (CONST LPMAT2)lpmat2, TRUE);
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
GetGlyphOutlineWow(
|
|
DWORD a0,
|
|
DWORD a1,
|
|
DWORD a2,
|
|
DWORD a3,
|
|
DWORD a4,
|
|
DWORD a5,
|
|
DWORD a6
|
|
)
|
|
{
|
|
UNIMPLEMENTED;
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
UINT
|
|
APIENTRY
|
|
GetOutlineTextMetricsA(
|
|
HDC hdc,
|
|
UINT cbData,
|
|
LPOUTLINETEXTMETRICA lpOTM
|
|
)
|
|
{
|
|
char buf[512], *ptr;
|
|
UINT ret, needed;
|
|
OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
|
|
OUTLINETEXTMETRICA *output = lpOTM;
|
|
INT left, len;
|
|
|
|
if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
|
|
return 0;
|
|
if(ret > sizeof(buf))
|
|
{
|
|
lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
|
|
if (lpOTMW == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
GetOutlineTextMetricsW(hdc, ret, lpOTMW);
|
|
|
|
needed = sizeof(OUTLINETEXTMETRICA);
|
|
if(lpOTMW->otmpFamilyName)
|
|
needed += WideCharToMultiByte(CP_ACP, 0,
|
|
(WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFamilyName), -1,
|
|
NULL, 0, NULL, NULL);
|
|
if(lpOTMW->otmpFaceName)
|
|
needed += WideCharToMultiByte(CP_ACP, 0,
|
|
(WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFaceName), -1,
|
|
NULL, 0, NULL, NULL);
|
|
if(lpOTMW->otmpStyleName)
|
|
needed += WideCharToMultiByte(CP_ACP, 0,
|
|
(WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpStyleName), -1,
|
|
NULL, 0, NULL, NULL);
|
|
if(lpOTMW->otmpFullName)
|
|
needed += WideCharToMultiByte(CP_ACP, 0,
|
|
(WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFullName), -1,
|
|
NULL, 0, NULL, NULL);
|
|
|
|
if(!lpOTM)
|
|
{
|
|
ret = needed;
|
|
goto end;
|
|
}
|
|
|
|
DPRINT("needed = %u\n", needed);
|
|
if(needed > cbData)
|
|
{
|
|
/* Since the supplied buffer isn't big enough, we'll alloc one
|
|
that is and memcpy the first cbData bytes into the lpOTM at
|
|
the end. */
|
|
output = HeapAlloc(GetProcessHeap(), 0, needed);
|
|
if (output == NULL)
|
|
{
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
ret = output->otmSize = min(needed, cbData);
|
|
FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
|
|
output->otmFiller = 0;
|
|
output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
|
|
output->otmfsSelection = lpOTMW->otmfsSelection;
|
|
output->otmfsType = lpOTMW->otmfsType;
|
|
output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
|
|
output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
|
|
output->otmItalicAngle = lpOTMW->otmItalicAngle;
|
|
output->otmEMSquare = lpOTMW->otmEMSquare;
|
|
output->otmAscent = lpOTMW->otmAscent;
|
|
output->otmDescent = lpOTMW->otmDescent;
|
|
output->otmLineGap = lpOTMW->otmLineGap;
|
|
output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
|
|
output->otmsXHeight = lpOTMW->otmsXHeight;
|
|
output->otmrcFontBox = lpOTMW->otmrcFontBox;
|
|
output->otmMacAscent = lpOTMW->otmMacAscent;
|
|
output->otmMacDescent = lpOTMW->otmMacDescent;
|
|
output->otmMacLineGap = lpOTMW->otmMacLineGap;
|
|
output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
|
|
output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
|
|
output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
|
|
output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
|
|
output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
|
|
output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
|
|
output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
|
|
output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
|
|
output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
|
|
|
|
|
|
ptr = (char*)(output + 1);
|
|
left = needed - sizeof(*output);
|
|
|
|
if(lpOTMW->otmpFamilyName)
|
|
{
|
|
output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
|
|
len = WideCharToMultiByte(CP_ACP, 0,
|
|
(WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFamilyName), -1,
|
|
ptr, left, NULL, NULL);
|
|
left -= len;
|
|
ptr += len;
|
|
}
|
|
else
|
|
output->otmpFamilyName = 0;
|
|
|
|
if(lpOTMW->otmpFaceName)
|
|
{
|
|
output->otmpFaceName = (LPSTR)(ptr - (char*)output);
|
|
len = WideCharToMultiByte(CP_ACP, 0,
|
|
(WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFaceName), -1,
|
|
ptr, left, NULL, NULL);
|
|
left -= len;
|
|
ptr += len;
|
|
}
|
|
else
|
|
output->otmpFaceName = 0;
|
|
|
|
if(lpOTMW->otmpStyleName)
|
|
{
|
|
output->otmpStyleName = (LPSTR)(ptr - (char*)output);
|
|
len = WideCharToMultiByte(CP_ACP, 0,
|
|
(WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpStyleName), -1,
|
|
ptr, left, NULL, NULL);
|
|
left -= len;
|
|
ptr += len;
|
|
}
|
|
else
|
|
output->otmpStyleName = 0;
|
|
|
|
if(lpOTMW->otmpFullName)
|
|
{
|
|
output->otmpFullName = (LPSTR)(ptr - (char*)output);
|
|
len = WideCharToMultiByte(CP_ACP, 0,
|
|
(WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFullName), -1,
|
|
ptr, left, NULL, NULL);
|
|
left -= len;
|
|
}
|
|
else
|
|
output->otmpFullName = 0;
|
|
|
|
ASSERT(left == 0);
|
|
|
|
if(output != lpOTM)
|
|
{
|
|
memcpy(lpOTM, output, cbData);
|
|
HeapFree(GetProcessHeap(), 0, output);
|
|
|
|
/* check if the string offsets really fit into the provided size */
|
|
/* FIXME: should we check string length as well? */
|
|
if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
|
|
lpOTM->otmpFamilyName = 0; /* doesn't fit */
|
|
|
|
if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
|
|
lpOTM->otmpFaceName = 0; /* doesn't fit */
|
|
|
|
if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
|
|
lpOTM->otmpStyleName = 0; /* doesn't fit */
|
|
|
|
if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
|
|
lpOTM->otmpFullName = 0; /* doesn't fit */
|
|
}
|
|
|
|
end:
|
|
if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
|
|
HeapFree(GetProcessHeap(), 0, lpOTMW);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Performs a device to world transformation on the specified size (which
|
|
* is in integer format).
|
|
*/
|
|
static inline INT INTERNAL_YDSTOWS(XFORM *xForm, INT height)
|
|
{
|
|
double floatHeight;
|
|
|
|
/* Perform operation with floating point */
|
|
floatHeight = (double)height * xForm->eM22;
|
|
/* Round to integers */
|
|
return GDI_ROUND(floatHeight);
|
|
}
|
|
|
|
/* scale width and height but don't mirror them */
|
|
static inline INT width_to_LP( XFORM *xForm, INT width )
|
|
{
|
|
return GDI_ROUND( (double)width * fabs( xForm->eM11));
|
|
}
|
|
|
|
static inline INT height_to_LP( XFORM *xForm, INT height )
|
|
{
|
|
return GDI_ROUND( (double)height * fabs( xForm->eM22 ));
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
UINT
|
|
APIENTRY
|
|
GetOutlineTextMetricsW(
|
|
HDC hdc,
|
|
UINT cbData,
|
|
LPOUTLINETEXTMETRICW lpOTM
|
|
)
|
|
{
|
|
TMDIFF Tmd; // Should not be zero.
|
|
UINT Size, AvailableSize = 0, StringSize;
|
|
XFORM DevToWorld;
|
|
OUTLINETEXTMETRICW* LocalOTM;
|
|
WCHAR* Str;
|
|
BYTE* Ptr;
|
|
|
|
/* Get the structure */
|
|
Size = NtGdiGetOutlineTextMetricsInternalW(hdc, 0, NULL, &Tmd);
|
|
if (!Size)
|
|
return 0;
|
|
if (!lpOTM || (cbData < sizeof(*lpOTM)))
|
|
return Size;
|
|
|
|
LocalOTM = HeapAlloc(GetProcessHeap(), 0, Size);
|
|
LocalOTM->otmSize = Size;
|
|
Size = NtGdiGetOutlineTextMetricsInternalW(hdc, Size, LocalOTM, &Tmd);
|
|
if (!Size)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, LocalOTM);
|
|
return 0;
|
|
}
|
|
|
|
if (!NtGdiGetTransform(hdc, GdiDeviceSpaceToWorldSpace, &DevToWorld))
|
|
{
|
|
DPRINT1("NtGdiGetTransform failed!\n");
|
|
HeapFree(GetProcessHeap(), 0, LocalOTM);
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return 0;
|
|
}
|
|
|
|
/* Fill in DC specific data */
|
|
LocalOTM->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
|
|
LocalOTM->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
|
|
LocalOTM->otmTextMetrics.tmHeight = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmHeight );
|
|
LocalOTM->otmTextMetrics.tmAscent = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmAscent );
|
|
LocalOTM->otmTextMetrics.tmDescent = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmDescent );
|
|
LocalOTM->otmTextMetrics.tmInternalLeading = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmInternalLeading );
|
|
LocalOTM->otmTextMetrics.tmExternalLeading = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmExternalLeading );
|
|
LocalOTM->otmTextMetrics.tmAveCharWidth = width_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmAveCharWidth );
|
|
LocalOTM->otmTextMetrics.tmMaxCharWidth = width_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmMaxCharWidth );
|
|
LocalOTM->otmTextMetrics.tmOverhang = width_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmOverhang );
|
|
LocalOTM->otmAscent = height_to_LP( &DevToWorld, LocalOTM->otmAscent);
|
|
LocalOTM->otmDescent = height_to_LP( &DevToWorld, LocalOTM->otmDescent);
|
|
LocalOTM->otmLineGap = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmLineGap));
|
|
LocalOTM->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmsCapEmHeight));
|
|
LocalOTM->otmsXHeight = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmsXHeight));
|
|
LocalOTM->otmrcFontBox.top = height_to_LP( &DevToWorld, LocalOTM->otmrcFontBox.top);
|
|
LocalOTM->otmrcFontBox.bottom = height_to_LP( &DevToWorld, LocalOTM->otmrcFontBox.bottom);
|
|
LocalOTM->otmrcFontBox.left = width_to_LP( &DevToWorld, LocalOTM->otmrcFontBox.left);
|
|
LocalOTM->otmrcFontBox.right = width_to_LP( &DevToWorld, LocalOTM->otmrcFontBox.right);
|
|
LocalOTM->otmMacAscent = height_to_LP( &DevToWorld, LocalOTM->otmMacAscent);
|
|
LocalOTM->otmMacDescent = height_to_LP( &DevToWorld, LocalOTM->otmMacDescent);
|
|
LocalOTM->otmMacLineGap = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmMacLineGap));
|
|
LocalOTM->otmptSubscriptSize.x = width_to_LP( &DevToWorld, LocalOTM->otmptSubscriptSize.x);
|
|
LocalOTM->otmptSubscriptSize.y = height_to_LP( &DevToWorld, LocalOTM->otmptSubscriptSize.y);
|
|
LocalOTM->otmptSubscriptOffset.x = width_to_LP( &DevToWorld, LocalOTM->otmptSubscriptOffset.x);
|
|
LocalOTM->otmptSubscriptOffset.y = height_to_LP( &DevToWorld, LocalOTM->otmptSubscriptOffset.y);
|
|
LocalOTM->otmptSuperscriptSize.x = width_to_LP( &DevToWorld, LocalOTM->otmptSuperscriptSize.x);
|
|
LocalOTM->otmptSuperscriptSize.y = height_to_LP( &DevToWorld, LocalOTM->otmptSuperscriptSize.y);
|
|
LocalOTM->otmptSuperscriptOffset.x = width_to_LP( &DevToWorld, LocalOTM->otmptSuperscriptOffset.x);
|
|
LocalOTM->otmptSuperscriptOffset.y = height_to_LP( &DevToWorld, LocalOTM->otmptSuperscriptOffset.y);
|
|
LocalOTM->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmsStrikeoutSize));
|
|
LocalOTM->otmsStrikeoutPosition = height_to_LP( &DevToWorld, LocalOTM->otmsStrikeoutPosition);
|
|
LocalOTM->otmsUnderscoreSize = height_to_LP( &DevToWorld, LocalOTM->otmsUnderscoreSize);
|
|
LocalOTM->otmsUnderscorePosition = height_to_LP( &DevToWorld, LocalOTM->otmsUnderscorePosition);
|
|
|
|
/* Copy what we can */
|
|
CopyMemory(lpOTM, LocalOTM, min(Size, cbData));
|
|
|
|
lpOTM->otmpFamilyName = NULL;
|
|
lpOTM->otmpFaceName = NULL;
|
|
lpOTM->otmpStyleName = NULL;
|
|
lpOTM->otmpFullName = NULL;
|
|
|
|
Size = sizeof(*lpOTM);
|
|
AvailableSize = cbData - Size;
|
|
Ptr = (BYTE*)lpOTM + sizeof(*lpOTM);
|
|
|
|
/* Fix string values up */
|
|
if (LocalOTM->otmpFamilyName)
|
|
{
|
|
Str = (WCHAR*)((char*)LocalOTM + (ptrdiff_t)LocalOTM->otmpFamilyName);
|
|
StringSize = (wcslen(Str) + 1) * sizeof(WCHAR);
|
|
if (AvailableSize >= StringSize)
|
|
{
|
|
CopyMemory(Ptr, Str, StringSize);
|
|
lpOTM->otmpFamilyName = (PSTR)(Ptr - (BYTE*)lpOTM);
|
|
Ptr += StringSize;
|
|
AvailableSize -= StringSize;
|
|
Size += StringSize;
|
|
}
|
|
}
|
|
|
|
if (LocalOTM->otmpFaceName)
|
|
{
|
|
Str = (WCHAR*)((char*)LocalOTM + (ptrdiff_t)LocalOTM->otmpFaceName);
|
|
StringSize = (wcslen(Str) + 1) * sizeof(WCHAR);
|
|
if (AvailableSize >= StringSize)
|
|
{
|
|
CopyMemory(Ptr, Str, StringSize);
|
|
lpOTM->otmpFaceName = (PSTR)(Ptr - (BYTE*)lpOTM);
|
|
Ptr += StringSize;
|
|
AvailableSize -= StringSize;
|
|
Size += StringSize;
|
|
}
|
|
}
|
|
|
|
if (LocalOTM->otmpStyleName)
|
|
{
|
|
Str = (WCHAR*)((char*)LocalOTM + (ptrdiff_t)LocalOTM->otmpStyleName);
|
|
StringSize = (wcslen(Str) + 1) * sizeof(WCHAR);
|
|
if (AvailableSize >= StringSize)
|
|
{
|
|
CopyMemory(Ptr, Str, StringSize);
|
|
lpOTM->otmpStyleName = (PSTR)(Ptr - (BYTE*)lpOTM);
|
|
Ptr += StringSize;
|
|
AvailableSize -= StringSize;
|
|
Size += StringSize;
|
|
}
|
|
}
|
|
|
|
if (LocalOTM->otmpFullName)
|
|
{
|
|
Str = (WCHAR*)((char*)LocalOTM + (ptrdiff_t)LocalOTM->otmpFullName);
|
|
StringSize = (wcslen(Str) + 1) * sizeof(WCHAR);
|
|
if (AvailableSize >= StringSize)
|
|
{
|
|
CopyMemory(Ptr, Str, StringSize);
|
|
lpOTM->otmpFullName = (PSTR)(Ptr - (BYTE*)lpOTM);
|
|
Ptr += StringSize;
|
|
AvailableSize -= StringSize;
|
|
Size += StringSize;
|
|
}
|
|
}
|
|
|
|
lpOTM->otmSize = Size;
|
|
|
|
HeapFree(GetProcessHeap(), 0, LocalOTM);
|
|
|
|
return Size;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
GetKerningPairsW(HDC hdc,
|
|
ULONG cPairs,
|
|
LPKERNINGPAIR pkpDst)
|
|
{
|
|
if ((cPairs != 0) || (pkpDst == 0))
|
|
{
|
|
return NtGdiGetKerningPairs(hdc,cPairs,pkpDst);
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
GetKerningPairsA( HDC hDC,
|
|
DWORD cPairs,
|
|
LPKERNINGPAIR kern_pairA )
|
|
{
|
|
INT charset;
|
|
CHARSETINFO csi;
|
|
CPINFO cpi;
|
|
DWORD i, total_kern_pairs, kern_pairs_copied = 0;
|
|
KERNINGPAIR *kern_pairW;
|
|
|
|
if (!cPairs && kern_pairA)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
charset = GetTextCharset(hDC);
|
|
if (!TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET))
|
|
{
|
|
DPRINT1("Can't find codepage for charset %d\n", charset);
|
|
return 0;
|
|
}
|
|
/* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
|
|
* to fail on an invalid character for CP_SYMBOL.
|
|
*/
|
|
cpi.DefaultChar[0] = 0;
|
|
if (csi.ciACP != CP_SYMBOL && !GetCPInfo(csi.ciACP, &cpi))
|
|
{
|
|
DPRINT1("Can't find codepage %u info\n", csi.ciACP);
|
|
return 0;
|
|
}
|
|
DPRINT("charset %d => codepage %u\n", charset, csi.ciACP);
|
|
|
|
total_kern_pairs = NtGdiGetKerningPairs(hDC, 0, NULL);
|
|
if (!total_kern_pairs) return 0;
|
|
|
|
if (!cPairs && !kern_pairA) return total_kern_pairs;
|
|
|
|
kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
|
|
if (kern_pairW == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
|
|
|
|
for (i = 0; i < total_kern_pairs; i++)
|
|
{
|
|
char first, second;
|
|
|
|
if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
|
|
continue;
|
|
|
|
if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
|
|
continue;
|
|
|
|
if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
|
|
continue;
|
|
|
|
if (kern_pairA)
|
|
{
|
|
if (kern_pairs_copied >= cPairs) break;
|
|
|
|
kern_pairA->wFirst = (BYTE)first;
|
|
kern_pairA->wSecond = (BYTE)second;
|
|
kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
|
|
kern_pairA++;
|
|
}
|
|
kern_pairs_copied++;
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, kern_pairW);
|
|
|
|
return kern_pairs_copied;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HFONT
|
|
WINAPI
|
|
CreateFontIndirectExA(const ENUMLOGFONTEXDVA *elfexd)
|
|
{
|
|
if (elfexd)
|
|
{
|
|
ENUMLOGFONTEXDVW Logfont;
|
|
|
|
EnumLogFontExW2A( (LPENUMLOGFONTEXA) elfexd,
|
|
&Logfont.elfEnumLogfontEx );
|
|
|
|
RtlCopyMemory( &Logfont.elfDesignVector,
|
|
(PVOID) &elfexd->elfDesignVector,
|
|
sizeof(DESIGNVECTOR));
|
|
|
|
return NtGdiHfontCreate( &Logfont, 0, 0, 0, NULL);
|
|
}
|
|
else return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HFONT
|
|
WINAPI
|
|
CreateFontIndirectExW(const ENUMLOGFONTEXDVW *elfexd)
|
|
{
|
|
/* Msdn: Note, this function ignores the elfDesignVector member in
|
|
ENUMLOGFONTEXDV.
|
|
*/
|
|
if ( elfexd )
|
|
{
|
|
return NtGdiHfontCreate((PENUMLOGFONTEXDVW) elfexd, 0, 0, 0, NULL );
|
|
}
|
|
else return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HFONT
|
|
WINAPI
|
|
CreateFontIndirectA(
|
|
CONST LOGFONTA *lplf
|
|
)
|
|
{
|
|
if (lplf)
|
|
{
|
|
LOGFONTW tlf;
|
|
|
|
LogFontA2W(&tlf, lplf);
|
|
return CreateFontIndirectW(&tlf);
|
|
}
|
|
else return NULL;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
VOID DumpFamilyInfo(const FONTFAMILYINFO *Info, LONG Count)
|
|
{
|
|
LONG i;
|
|
const LOGFONTW *plf;
|
|
|
|
DPRINT1("---\n");
|
|
DPRINT1("Count: %d\n", Count);
|
|
for (i = 0; i < Count; ++i)
|
|
{
|
|
plf = &Info[i].EnumLogFontEx.elfLogFont;
|
|
DPRINT1("%d: '%S',%u,'%S', %ld:%ld, %ld, %d, %d\n", i,
|
|
plf->lfFaceName, plf->lfCharSet, Info[i].EnumLogFontEx.elfFullName,
|
|
plf->lfHeight, plf->lfWidth, plf->lfWeight, plf->lfItalic, plf->lfPitchAndFamily);
|
|
}
|
|
}
|
|
|
|
VOID DoFontSystemUnittest(VOID)
|
|
{
|
|
#ifndef RTL_SOFT_ASSERT
|
|
#define RTL_SOFT_ASSERT(exp) \
|
|
(void)((!(exp)) ? \
|
|
DbgPrint("%s(%d): Soft assertion failed\n Expression: %s\n", __FILE__, __LINE__, #exp), FALSE : TRUE)
|
|
#define RTL_SOFT_ASSERT_defined
|
|
#endif
|
|
|
|
LOGFONTW LogFont;
|
|
FONTFAMILYINFO Info[4];
|
|
UNICODE_STRING Str1, Str2;
|
|
LONG ret, InfoCount;
|
|
|
|
//DumpFontInfo(TRUE);
|
|
|
|
/* L"" DEFAULT_CHARSET */
|
|
RtlZeroMemory(&LogFont, sizeof(LogFont));
|
|
LogFont.lfCharSet = DEFAULT_CHARSET;
|
|
InfoCount = RTL_NUMBER_OF(Info);
|
|
ret = NtGdiGetFontFamilyInfo(NULL, &LogFont, Info, &InfoCount);
|
|
DPRINT1("ret: %ld, InfoCount: %ld\n", ret, InfoCount);
|
|
DumpFamilyInfo(Info, ret);
|
|
RTL_SOFT_ASSERT(ret == RTL_NUMBER_OF(Info));
|
|
RTL_SOFT_ASSERT(InfoCount > 32);
|
|
|
|
/* L"Microsoft Sans Serif" ANSI_CHARSET */
|
|
RtlZeroMemory(&LogFont, sizeof(LogFont));
|
|
LogFont.lfCharSet = ANSI_CHARSET;
|
|
StringCbCopyW(LogFont.lfFaceName, sizeof(LogFont.lfFaceName), L"Microsoft Sans Serif");
|
|
InfoCount = RTL_NUMBER_OF(Info);
|
|
ret = NtGdiGetFontFamilyInfo(NULL, &LogFont, Info, &InfoCount);
|
|
DPRINT1("ret: %ld, InfoCount: %ld\n", ret, InfoCount);
|
|
DumpFamilyInfo(Info, ret);
|
|
RTL_SOFT_ASSERT(ret != -1);
|
|
RTL_SOFT_ASSERT(InfoCount > 0);
|
|
RTL_SOFT_ASSERT(InfoCount < 16);
|
|
|
|
RtlInitUnicodeString(&Str1, Info[0].EnumLogFontEx.elfLogFont.lfFaceName);
|
|
RtlInitUnicodeString(&Str2, L"Microsoft Sans Serif");
|
|
ret = RtlCompareUnicodeString(&Str1, &Str2, TRUE);
|
|
RTL_SOFT_ASSERT(ret == 0);
|
|
|
|
RtlInitUnicodeString(&Str1, Info[0].EnumLogFontEx.elfFullName);
|
|
RtlInitUnicodeString(&Str2, L"Tahoma");
|
|
ret = RtlCompareUnicodeString(&Str1, &Str2, TRUE);
|
|
RTL_SOFT_ASSERT(ret == 0);
|
|
|
|
/* L"Non-Existent" DEFAULT_CHARSET */
|
|
RtlZeroMemory(&LogFont, sizeof(LogFont));
|
|
LogFont.lfCharSet = ANSI_CHARSET;
|
|
StringCbCopyW(LogFont.lfFaceName, sizeof(LogFont.lfFaceName), L"Non-Existent");
|
|
InfoCount = RTL_NUMBER_OF(Info);
|
|
ret = NtGdiGetFontFamilyInfo(NULL, &LogFont, Info, &InfoCount);
|
|
DPRINT1("ret: %ld, InfoCount: %ld\n", ret, InfoCount);
|
|
DumpFamilyInfo(Info, ret);
|
|
RTL_SOFT_ASSERT(ret == 0);
|
|
RTL_SOFT_ASSERT(InfoCount == 0);
|
|
|
|
#ifdef RTL_SOFT_ASSERT_defined
|
|
#undef RTL_SOFT_ASSERT_defined
|
|
#undef RTL_SOFT_ASSERT
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/* EOF */
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HFONT
|
|
WINAPI
|
|
CreateFontIndirectW(
|
|
CONST LOGFONTW *lplf
|
|
)
|
|
{
|
|
#if 0
|
|
static BOOL bDidTest = FALSE;
|
|
if (!bDidTest)
|
|
{
|
|
bDidTest = TRUE;
|
|
DoFontSystemUnittest();
|
|
}
|
|
#endif
|
|
if (lplf)
|
|
{
|
|
ENUMLOGFONTEXDVW Logfont;
|
|
|
|
RtlCopyMemory( &Logfont.elfEnumLogfontEx.elfLogFont, lplf, sizeof(LOGFONTW));
|
|
// Need something other than just cleaning memory here.
|
|
// Guess? Use caller data to determine the rest.
|
|
RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfFullName,
|
|
sizeof(Logfont.elfEnumLogfontEx.elfFullName));
|
|
RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfStyle,
|
|
sizeof(Logfont.elfEnumLogfontEx.elfStyle));
|
|
RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfScript,
|
|
sizeof(Logfont.elfEnumLogfontEx.elfScript));
|
|
|
|
Logfont.elfDesignVector.dvNumAxes = 0; // No more than MM_MAX_NUMAXES
|
|
|
|
RtlZeroMemory( &Logfont.elfDesignVector, sizeof(DESIGNVECTOR));
|
|
|
|
return CreateFontIndirectExW(&Logfont);
|
|
}
|
|
else return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HFONT
|
|
WINAPI
|
|
CreateFontA(
|
|
int nHeight,
|
|
int nWidth,
|
|
int nEscapement,
|
|
int nOrientation,
|
|
int fnWeight,
|
|
DWORD fdwItalic,
|
|
DWORD fdwUnderline,
|
|
DWORD fdwStrikeOut,
|
|
DWORD fdwCharSet,
|
|
DWORD fdwOutputPrecision,
|
|
DWORD fdwClipPrecision,
|
|
DWORD fdwQuality,
|
|
DWORD fdwPitchAndFamily,
|
|
LPCSTR lpszFace
|
|
)
|
|
{
|
|
ANSI_STRING StringA;
|
|
UNICODE_STRING StringU;
|
|
HFONT ret;
|
|
|
|
RtlInitAnsiString(&StringA, (LPSTR)lpszFace);
|
|
RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
|
|
|
|
ret = CreateFontW(nHeight,
|
|
nWidth,
|
|
nEscapement,
|
|
nOrientation,
|
|
fnWeight,
|
|
fdwItalic,
|
|
fdwUnderline,
|
|
fdwStrikeOut,
|
|
fdwCharSet,
|
|
fdwOutputPrecision,
|
|
fdwClipPrecision,
|
|
fdwQuality,
|
|
fdwPitchAndFamily,
|
|
StringU.Buffer);
|
|
|
|
RtlFreeUnicodeString(&StringU);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HFONT
|
|
WINAPI
|
|
CreateFontW(
|
|
int nHeight,
|
|
int nWidth,
|
|
int nEscapement,
|
|
int nOrientation,
|
|
int nWeight,
|
|
DWORD fnItalic,
|
|
DWORD fdwUnderline,
|
|
DWORD fdwStrikeOut,
|
|
DWORD fdwCharSet,
|
|
DWORD fdwOutputPrecision,
|
|
DWORD fdwClipPrecision,
|
|
DWORD fdwQuality,
|
|
DWORD fdwPitchAndFamily,
|
|
LPCWSTR lpszFace
|
|
)
|
|
{
|
|
LOGFONTW logfont;
|
|
|
|
logfont.lfHeight = nHeight;
|
|
logfont.lfWidth = nWidth;
|
|
logfont.lfEscapement = nEscapement;
|
|
logfont.lfOrientation = nOrientation;
|
|
logfont.lfWeight = nWeight;
|
|
logfont.lfItalic = (BYTE)fnItalic;
|
|
logfont.lfUnderline = (BYTE)fdwUnderline;
|
|
logfont.lfStrikeOut = (BYTE)fdwStrikeOut;
|
|
logfont.lfCharSet = (BYTE)fdwCharSet;
|
|
logfont.lfOutPrecision = (BYTE)fdwOutputPrecision;
|
|
logfont.lfClipPrecision = (BYTE)fdwClipPrecision;
|
|
logfont.lfQuality = (BYTE)fdwQuality;
|
|
logfont.lfPitchAndFamily = (BYTE)fdwPitchAndFamily;
|
|
|
|
if (NULL != lpszFace)
|
|
{
|
|
int Size = sizeof(logfont.lfFaceName) / sizeof(WCHAR);
|
|
wcsncpy((wchar_t *)logfont.lfFaceName, lpszFace, Size - 1);
|
|
/* Be 101% sure to have '\0' at end of string */
|
|
logfont.lfFaceName[Size - 1] = '\0';
|
|
}
|
|
else
|
|
{
|
|
logfont.lfFaceName[0] = L'\0';
|
|
}
|
|
|
|
return CreateFontIndirectW(&logfont);
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
CreateScalableFontResourceA(
|
|
DWORD fdwHidden,
|
|
LPCSTR lpszFontRes,
|
|
LPCSTR lpszFontFile,
|
|
LPCSTR lpszCurrentPath
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
int
|
|
WINAPI
|
|
AddFontResourceExW ( LPCWSTR lpszFilename, DWORD fl, PVOID pvReserved )
|
|
{
|
|
if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return 0;
|
|
}
|
|
|
|
return GdiAddFontResourceW(lpszFilename, fl,0);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
int
|
|
WINAPI
|
|
AddFontResourceExA ( LPCSTR lpszFilename, DWORD fl, PVOID pvReserved )
|
|
{
|
|
NTSTATUS Status;
|
|
PWSTR FilenameW;
|
|
int rc;
|
|
|
|
if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return 0;
|
|
}
|
|
|
|
Status = HEAP_strdupA2W ( &FilenameW, lpszFilename );
|
|
if ( !NT_SUCCESS (Status) )
|
|
{
|
|
SetLastError (RtlNtStatusToDosError(Status));
|
|
return 0;
|
|
}
|
|
|
|
rc = GdiAddFontResourceW ( FilenameW, fl, 0 );
|
|
HEAP_free ( FilenameW );
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
int
|
|
WINAPI
|
|
AddFontResourceA ( LPCSTR lpszFilename )
|
|
{
|
|
NTSTATUS Status;
|
|
PWSTR FilenameW;
|
|
int rc = 0;
|
|
|
|
Status = HEAP_strdupA2W ( &FilenameW, lpszFilename );
|
|
if ( !NT_SUCCESS (Status) )
|
|
{
|
|
SetLastError (RtlNtStatusToDosError(Status));
|
|
}
|
|
else
|
|
{
|
|
rc = GdiAddFontResourceW ( FilenameW, 0, 0);
|
|
|
|
HEAP_free ( FilenameW );
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
int
|
|
WINAPI
|
|
AddFontResourceW ( LPCWSTR lpszFilename )
|
|
{
|
|
return GdiAddFontResourceW ( lpszFilename, 0, 0 );
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
RemoveFontResourceW(LPCWSTR lpFileName)
|
|
{
|
|
return RemoveFontResourceExW(lpFileName,0,0);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
RemoveFontResourceA(LPCSTR lpFileName)
|
|
{
|
|
return RemoveFontResourceExA(lpFileName,0,0);
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
RemoveFontResourceExA(LPCSTR lpFileName,
|
|
DWORD fl,
|
|
PVOID pdv
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
LPWSTR lpFileNameW;
|
|
|
|
/* FIXME the flags */
|
|
/* FIXME the pdv */
|
|
/* FIXME NtGdiRemoveFontResource handle flags and pdv */
|
|
|
|
Status = HEAP_strdupA2W ( &lpFileNameW, lpFileName );
|
|
if (!NT_SUCCESS (Status))
|
|
SetLastError (RtlNtStatusToDosError(Status));
|
|
else
|
|
{
|
|
|
|
HEAP_free ( lpFileNameW );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
RemoveFontResourceExW(LPCWSTR lpFileName,
|
|
DWORD fl,
|
|
PVOID pdv)
|
|
{
|
|
/* FIXME the flags */
|
|
/* FIXME the pdv */
|
|
/* FIXME NtGdiRemoveFontResource handle flags and pdv */
|
|
DPRINT("RemoveFontResourceExW\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GdiGetCharDimensions
|
|
*
|
|
* Gets the average width of the characters in the English alphabet.
|
|
*
|
|
* PARAMS
|
|
* hdc [I] Handle to the device context to measure on.
|
|
* lptm [O] Pointer to memory to store the text metrics into.
|
|
* height [O] On exit, the maximum height of characters in the English alphabet.
|
|
*
|
|
* RETURNS
|
|
* The average width of characters in the English alphabet.
|
|
*
|
|
* NOTES
|
|
* This function is used by the dialog manager to get the size of a dialog
|
|
* unit. It should also be used by other pieces of code that need to know
|
|
* the size of a dialog unit in logical units without having access to the
|
|
* window handle of the dialog.
|
|
* Windows caches the font metrics from this function, but we don't and
|
|
* there doesn't appear to be an immediate advantage to do so.
|
|
*
|
|
* SEE ALSO
|
|
* GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
|
|
*
|
|
* Despite most of MSDN insisting that the horizontal base unit is
|
|
* tmAveCharWidth it isn't. Knowledge base article Q145994
|
|
* "HOWTO: Calculate Dialog Units When Not Using the System Font",
|
|
* says that we should take the average of the 52 English upper and lower
|
|
* case characters.
|
|
*/
|
|
/*
|
|
* @implemented
|
|
*/
|
|
LONG
|
|
WINAPI
|
|
GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
|
|
{
|
|
SIZE sz;
|
|
TEXTMETRICW tm;
|
|
static const WCHAR alphabet[] =
|
|
{
|
|
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
|
|
'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
|
|
'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0
|
|
};
|
|
|
|
if(!GetTextMetricsW(hdc, &tm)) return 0;
|
|
|
|
if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
|
|
|
|
if (lptm) *lptm = tm;
|
|
if (height) *height = tm.tmHeight;
|
|
|
|
return (sz.cx / 26 + 1) / 2;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* TranslateCharsetInfo [GDI32.@]
|
|
*
|
|
* 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 lpCs->fs. If TCI_SRCFONTSIG is used,
|
|
* only one codepage should be set in *lpSrc.
|
|
*
|
|
* RETURNS
|
|
* TRUE on success, FALSE on failure.
|
|
*
|
|
*/
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
TranslateCharsetInfo(
|
|
LPDWORD lpSrc, /* [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 lpCs, /* [out] structure to receive charset information */
|
|
DWORD flags /* [in] determines interpretation of lpSrc */)
|
|
{
|
|
int index = 0;
|
|
switch (flags)
|
|
{
|
|
case TCI_SRCFONTSIG:
|
|
while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
|
|
break;
|
|
case TCI_SRCCODEPAGE:
|
|
while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
|
|
break;
|
|
case TCI_SRCCHARSET:
|
|
while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
|
|
break;
|
|
case TCI_SRCLOCALE:
|
|
{
|
|
LCID lCid = (LCID)PtrToUlong(lpSrc);
|
|
LOCALESIGNATURE LocSig;
|
|
INT Ret = GetLocaleInfoW(lCid, LOCALE_FONTSIGNATURE, (LPWSTR)&LocSig, 0);
|
|
if ( GetLocaleInfoW(lCid, LOCALE_FONTSIGNATURE, (LPWSTR)&LocSig, Ret))
|
|
{
|
|
while (index < MAXTCIINDEX && !(LocSig.lsCsbDefault[0]>>index & 0x0001)) index++;
|
|
break;
|
|
}
|
|
}
|
|
default:
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
|
|
DPRINT("Index %d Charset %u CodePage %u FontSig %lu\n",
|
|
index,FONT_tci[index].ciCharset,FONT_tci[index].ciACP,FONT_tci[index].fs.fsCsb[0]);
|
|
memcpy(lpCs, &FONT_tci[index], sizeof(CHARSETINFO));
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
SetMapperFlags(
|
|
HDC hDC,
|
|
DWORD flags
|
|
)
|
|
{
|
|
DWORD Ret = GDI_ERROR;
|
|
PDC_ATTR Dc_Attr;
|
|
|
|
/* Get the DC attribute */
|
|
Dc_Attr = GdiGetDcAttr(hDC);
|
|
if (Dc_Attr == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return GDI_ERROR;
|
|
}
|
|
|
|
if (NtCurrentTeb()->GdiTebBatch.HDC == hDC)
|
|
{
|
|
if (Dc_Attr->ulDirty_ & DC_FONTTEXT_DIRTY)
|
|
{
|
|
NtGdiFlush();
|
|
Dc_Attr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY);
|
|
}
|
|
}
|
|
|
|
if ( flags & ~1 )
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
else
|
|
{
|
|
Ret = Dc_Attr->flFontMapper;
|
|
Dc_Attr->flFontMapper = flags;
|
|
}
|
|
return Ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
int
|
|
WINAPI
|
|
EnumFontsW(
|
|
HDC hDC,
|
|
LPCWSTR lpFaceName,
|
|
FONTENUMPROCW FontFunc,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
#if 0
|
|
return NtGdiEnumFonts ( hDC, lpFaceName, FontFunc, lParam );
|
|
#else
|
|
return EnumFontFamiliesW( hDC, lpFaceName, FontFunc, lParam );
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
int
|
|
WINAPI
|
|
EnumFontsA (
|
|
HDC hDC,
|
|
LPCSTR lpFaceName,
|
|
FONTENUMPROCA FontFunc,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
#if 0
|
|
NTSTATUS Status;
|
|
LPWSTR lpFaceNameW;
|
|
int rc = 0;
|
|
|
|
Status = HEAP_strdupA2W ( &lpFaceNameW, lpFaceName );
|
|
if (!NT_SUCCESS (Status))
|
|
SetLastError (RtlNtStatusToDosError(Status));
|
|
else
|
|
{
|
|
rc = NtGdiEnumFonts ( hDC, lpFaceNameW, FontFunc, lParam );
|
|
|
|
HEAP_free ( lpFaceNameW );
|
|
}
|
|
return rc;
|
|
#else
|
|
return EnumFontFamiliesA( hDC, lpFaceName, FontFunc, lParam );
|
|
#endif
|
|
}
|
|
|
|
#define EfdFontFamilies 3
|
|
|
|
INT
|
|
WINAPI
|
|
NewEnumFontFamiliesExW(
|
|
HDC hDC,
|
|
LPLOGFONTW lpLogfont,
|
|
FONTENUMPROCW lpEnumFontFamExProcW,
|
|
LPARAM lParam,
|
|
DWORD dwFlags)
|
|
{
|
|
ULONG_PTR idEnum;
|
|
ULONG cbDataSize, cbRetSize;
|
|
PENUMFONTDATAW pEfdw;
|
|
PBYTE pBuffer;
|
|
PBYTE pMax;
|
|
INT ret = 1;
|
|
|
|
/* Open enumeration handle and find out how much memory we need */
|
|
idEnum = NtGdiEnumFontOpen(hDC,
|
|
EfdFontFamilies,
|
|
0,
|
|
LF_FACESIZE,
|
|
(lpLogfont && lpLogfont->lfFaceName[0])? lpLogfont->lfFaceName : NULL,
|
|
lpLogfont? lpLogfont->lfCharSet : DEFAULT_CHARSET,
|
|
&cbDataSize);
|
|
if (idEnum == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
if (cbDataSize == 0)
|
|
{
|
|
NtGdiEnumFontClose(idEnum);
|
|
return 0;
|
|
}
|
|
|
|
/* Allocate memory */
|
|
pBuffer = HeapAlloc(GetProcessHeap(), 0, cbDataSize);
|
|
if (pBuffer == NULL)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
NtGdiEnumFontClose(idEnum);
|
|
return 0;
|
|
}
|
|
|
|
/* Do the enumeration */
|
|
if (!NtGdiEnumFontChunk(hDC, idEnum, cbDataSize, &cbRetSize, (PVOID)pBuffer))
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, pBuffer);
|
|
NtGdiEnumFontClose(idEnum);
|
|
return 0;
|
|
}
|
|
|
|
/* Get start and end address */
|
|
pEfdw = (PENUMFONTDATAW)pBuffer;
|
|
pMax = pBuffer + cbDataSize;
|
|
|
|
/* Iterate through the structures */
|
|
while ((PBYTE)pEfdw < pMax && ret)
|
|
{
|
|
PNTMW_INTERNAL pNtmwi = (PNTMW_INTERNAL)((ULONG_PTR)pEfdw + pEfdw->ulNtmwiOffset);
|
|
|
|
ret = lpEnumFontFamExProcW((VOID*)&pEfdw->elfexdv.elfEnumLogfontEx,
|
|
(VOID*)&pNtmwi->ntmw,
|
|
pEfdw->dwFontType,
|
|
lParam);
|
|
|
|
pEfdw = (PENUMFONTDATAW)((ULONG_PTR)pEfdw + pEfdw->cbSize);
|
|
}
|
|
|
|
/* Release the memory and close handle */
|
|
HeapFree(GetProcessHeap(), 0, pBuffer);
|
|
NtGdiEnumFontClose(idEnum);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
int
|
|
WINAPI
|
|
GdiAddFontResourceW(
|
|
LPCWSTR lpszFilename,
|
|
FLONG fl,
|
|
DESIGNVECTOR *pdv)
|
|
{
|
|
INT Ret;
|
|
WCHAR lpszBuffer[MAX_PATH];
|
|
WCHAR lpszAbsPath[MAX_PATH];
|
|
UNICODE_STRING NtAbsPath;
|
|
|
|
/* FIXME: We don't support multiple files passed in lpszFilename
|
|
* as L"abcxxxxx.pfm|abcxxxxx.pfb"
|
|
*/
|
|
|
|
/* Does the file exist in CurrentDirectory or in the Absolute Path passed? */
|
|
GetCurrentDirectoryW(MAX_PATH, lpszBuffer);
|
|
|
|
if (!SearchPathW(lpszBuffer, lpszFilename, NULL, MAX_PATH, lpszAbsPath, NULL))
|
|
{
|
|
/* Nope. Then let's check Fonts folder */
|
|
GetWindowsDirectoryW(lpszBuffer, MAX_PATH);
|
|
StringCbCatW(lpszBuffer, sizeof(lpszBuffer), L"\\Fonts");
|
|
|
|
if (!SearchPathW(lpszBuffer, lpszFilename, NULL, MAX_PATH, lpszAbsPath, NULL))
|
|
{
|
|
DPRINT1("Font not found. The Buffer is: %ls, the FileName is: %S\n", lpszBuffer, lpszFilename);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* We found the font file so: */
|
|
if (!RtlDosPathNameToNtPathName_U(lpszAbsPath, &NtAbsPath, NULL, NULL))
|
|
{
|
|
DPRINT1("Can't convert Path! Path: %ls\n", lpszAbsPath);
|
|
return 0;
|
|
}
|
|
|
|
/* The Nt call expects a null-terminator included in cwc param. */
|
|
ASSERT(NtAbsPath.Buffer[NtAbsPath.Length / sizeof(WCHAR)] == UNICODE_NULL);
|
|
Ret = NtGdiAddFontResourceW(NtAbsPath.Buffer, NtAbsPath.Length / sizeof(WCHAR) + 1, 1, fl, 0, pdv);
|
|
|
|
RtlFreeUnicodeString(&NtAbsPath);
|
|
|
|
return Ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
HANDLE
|
|
WINAPI
|
|
AddFontMemResourceEx(
|
|
PVOID pbFont,
|
|
DWORD cbFont,
|
|
PVOID pdv,
|
|
DWORD *pcFonts
|
|
)
|
|
{
|
|
if ( pbFont && cbFont && pcFonts)
|
|
{
|
|
return NtGdiAddFontMemResourceEx(pbFont, cbFont, NULL, 0, pcFonts);
|
|
}
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
RemoveFontMemResourceEx(HANDLE fh)
|
|
{
|
|
if (fh)
|
|
{
|
|
return NtGdiRemoveFontMemResourceEx(fh);
|
|
}
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
int
|
|
WINAPI
|
|
AddFontResourceTracking(
|
|
LPCSTR lpString,
|
|
int unknown
|
|
)
|
|
{
|
|
UNIMPLEMENTED;
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
int
|
|
WINAPI
|
|
RemoveFontResourceTracking(LPCSTR lpString,int unknown)
|
|
{
|
|
UNIMPLEMENTED;
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
CreateScalableFontResourceW(
|
|
DWORD fdwHidden,
|
|
LPCWSTR lpszFontRes,
|
|
LPCWSTR lpszFontFile,
|
|
LPCWSTR lpszCurrentPath
|
|
)
|
|
{
|
|
HANDLE f;
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
/* fHidden=1 - only visible for the calling app, read-only, not
|
|
* enumerated with EnumFonts/EnumFontFamilies
|
|
* lpszCurrentPath can be NULL
|
|
*/
|
|
|
|
/* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
|
|
if ((f = CreateFileW(lpszFontRes, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(f);
|
|
SetLastError(ERROR_FILE_EXISTS);
|
|
return FALSE;
|
|
}
|
|
return FALSE; /* create failed */
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
bInitSystemAndFontsDirectoriesW(LPWSTR *SystemDir,LPWSTR *FontsDir)
|
|
{
|
|
UNIMPLEMENTED;
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
EudcLoadLinkW(LPCWSTR pBaseFaceName,LPCWSTR pEudcFontPath,INT iPriority,INT iFontLinkType)
|
|
{
|
|
UNIMPLEMENTED;
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
EudcUnloadLinkW(LPCWSTR pBaseFaceName,LPCWSTR pEudcFontPath)
|
|
{
|
|
UNIMPLEMENTED;
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ULONG
|
|
WINAPI
|
|
GetEUDCTimeStamp(VOID)
|
|
{
|
|
return NtGdiGetEudcTimeStampEx(NULL,0,TRUE);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
GetEUDCTimeStampExW(LPWSTR lpBaseFaceName)
|
|
{
|
|
DWORD retValue = 0;
|
|
|
|
if (!lpBaseFaceName)
|
|
{
|
|
retValue = NtGdiGetEudcTimeStampEx(NULL,0,FALSE);
|
|
}
|
|
else
|
|
{
|
|
retValue = NtGdiGetEudcTimeStampEx(lpBaseFaceName, wcslen(lpBaseFaceName), FALSE);
|
|
}
|
|
|
|
return retValue;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ULONG
|
|
WINAPI
|
|
GetFontAssocStatus(HDC hdc)
|
|
{
|
|
ULONG retValue = 0;
|
|
|
|
if (hdc)
|
|
{
|
|
retValue = NtGdiQueryFontAssocInfo(hdc);
|
|
}
|
|
|
|
return retValue;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
QueryFontAssocStatus(VOID)
|
|
{
|
|
UNIMPLEMENTED;
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
VOID
|
|
WINAPI
|
|
UnloadNetworkFonts(DWORD unknown)
|
|
{
|
|
UNIMPLEMENTED;
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
GetFontData(HDC hdc,
|
|
DWORD dwTable,
|
|
DWORD dwOffset,
|
|
LPVOID lpvBuffer,
|
|
DWORD cbData)
|
|
{
|
|
if (!lpvBuffer)
|
|
{
|
|
cbData = 0;
|
|
}
|
|
return NtGdiGetFontData(hdc, dwTable, dwOffset, lpvBuffer, cbData);
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
cGetTTFFromFOT(DWORD x1 ,DWORD x2 ,DWORD x3, DWORD x4, DWORD x5, DWORD x6, DWORD x7)
|
|
{
|
|
UNIMPLEMENTED;
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return 0;
|
|
}
|
|
|