reactos/win32ss/gdi/ntgdi/font.c

1212 lines
27 KiB
C

/*
* PROJECT: ReactOS win32 kernel mode subsystem
* LICENSE: GPL - See COPYING in the top level directory
* FILE: win32ss/gdi/ntgdi/font.c
* PURPOSE: Font
* PROGRAMMERS: James Tabor <james.tabor@reactos.org>
* Timo Kreuzer <timo.kreuzer@reactos.org>
* Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
/** Includes ******************************************************************/
#include <win32k.h>
#define NDEBUG
#include <debug.h>
HFONT APIENTRY HfontCreate( IN PENUMLOGFONTEXDVW pelfw,IN ULONG cjElfw,IN LFTYPE lft,IN FLONG fl,IN PVOID pvCliData );
/** Internal ******************************************************************/
HFONT FASTCALL
GreCreateFontIndirectW( LOGFONTW *lplf )
{
if (lplf)
{
ENUMLOGFONTEXDVW Logfont;
RtlCopyMemory( &Logfont.elfEnumLogfontEx.elfLogFont, lplf, sizeof(LOGFONTW));
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;
RtlZeroMemory( &Logfont.elfDesignVector, sizeof(DESIGNVECTOR));
return HfontCreate((PENUMLOGFONTEXDVW)&Logfont, 0, 0, 0, NULL );
}
else return NULL;
}
DWORD
FASTCALL
GreGetKerningPairs(
HDC hDC,
ULONG NumPairs,
LPKERNINGPAIR krnpair)
{
PDC dc;
PDC_ATTR pdcattr;
PTEXTOBJ TextObj;
PFONTGDI FontGDI;
DWORD Count;
KERNINGPAIR *pKP;
dc = DC_LockDc(hDC);
if (!dc)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return 0;
}
pdcattr = dc->pdcattr;
TextObj = RealizeFontInit(pdcattr->hlfntNew);
DC_UnlockDc(dc);
if (!TextObj)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return 0;
}
FontGDI = ObjToGDI(TextObj->Font, FONT);
TEXTOBJ_UnlockText(TextObj);
Count = ftGdiGetKerningPairs(FontGDI,0,NULL);
if ( Count && krnpair )
{
if (Count > NumPairs)
{
EngSetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
pKP = ExAllocatePoolWithTag(PagedPool, Count * sizeof(KERNINGPAIR), GDITAG_TEXT);
if (!pKP)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
ftGdiGetKerningPairs(FontGDI,Count,pKP);
RtlCopyMemory(krnpair, pKP, Count * sizeof(KERNINGPAIR));
ExFreePoolWithTag(pKP,GDITAG_TEXT);
}
return Count;
}
/*
It is recommended that an application use the GetFontLanguageInfo function
to determine whether the GCP_DIACRITIC, GCP_DBCS, GCP_USEKERNING, GCP_LIGATE,
GCP_REORDER, GCP_GLYPHSHAPE, and GCP_KASHIDA values are valid for the
currently selected font. If not valid, GetCharacterPlacement ignores the
value.
M$ must use a preset "compiled in" support for each language based releases.
ReactOS uses FreeType, this will need to be supported. ATM this is hard coded
for GCPCLASS_LATIN!
*/
#if 0
DWORD
FASTCALL
GreGetCharacterPlacementW(
HDC hdc,
LPCWSTR pwsz,
INT nCount,
INT nMaxExtent,
LPGCP_RESULTSW pgcpw,
DWORD dwFlags)
{
GCP_RESULTSW gcpwSave;
UINT i, nSet, cSet;
INT *tmpDxCaretPos;
LONG Cx;
SIZE Size = {0,0};
DPRINT1("GreGCPW Start\n");
if (!pgcpw)
{
if (GreGetTextExtentW( hdc, pwsz, nCount, &Size, 1))
return MAKELONG(Size.cx, Size.cy);
return 0;
}
DPRINT1("GreGCPW 1\n");
RtlCopyMemory(&gcpwSave, pgcpw, sizeof(GCP_RESULTSW));
cSet = nSet = nCount;
if ( nCount > gcpwSave.nGlyphs ) cSet = gcpwSave.nGlyphs;
/* GCP_JUSTIFY may only be used in conjunction with GCP_MAXEXTENT. */
if ( dwFlags & GCP_JUSTIFY) dwFlags |= GCP_MAXEXTENT;
if ( !gcpwSave.lpDx && gcpwSave.lpCaretPos )
tmpDxCaretPos = gcpwSave.lpCaretPos;
else
tmpDxCaretPos = gcpwSave.lpDx;
if ( !GreGetTextExtentExW( hdc,
pwsz,
cSet,
nMaxExtent,
((dwFlags & GCP_MAXEXTENT) ? (PULONG) &cSet : NULL),
(PULONG) tmpDxCaretPos,
&Size,
0) )
{
return 0;
}
DPRINT1("GreGCPW 2\n");
nSet = cSet;
if ( tmpDxCaretPos && nSet > 0)
{
for (i = (nSet - 1); i > 0; i--)
{
tmpDxCaretPos[i] -= tmpDxCaretPos[i - 1];
}
}
if ( !(dwFlags & GCP_MAXEXTENT) || nSet )
{
if ( (dwFlags & GCP_USEKERNING) &&
( gcpwSave.lpDx ||
gcpwSave.lpCaretPos ) &&
nSet >= 2 )
{
DWORD Count;
LPKERNINGPAIR pKP;
Count = GreGetKerningPairs( hdc, 0, NULL);
if (Count)
{
pKP = ExAllocatePoolWithTag(PagedPool, Count * sizeof(KERNINGPAIR), GDITAG_TEXT);
if (pKP)
{
if ( GreGetKerningPairs( hdc, Count, pKP) != Count)
{
ExFreePoolWithTag( pKP, GDITAG_TEXT);
return 0;
}
if ( (ULONG_PTR)(pKP) < ((ULONG_PTR)(pKP) + (ULONG_PTR)(Count * sizeof(KERNINGPAIR))) )
{
DPRINT1("We Need to Do Something HERE!\n");
}
ExFreePoolWithTag( pKP, GDITAG_TEXT);
if ( dwFlags & GCP_MAXEXTENT )
{
if ( Size.cx > nMaxExtent )
{
for (Cx = Size.cx; nSet > 0; nSet--)
{
Cx -= tmpDxCaretPos[nSet - 1];
Size.cx = Cx;
if ( Cx <= nMaxExtent ) break;
}
}
if ( !nSet )
{
pgcpw->nGlyphs = 0;
pgcpw->nMaxFit = 0;
return 0;
}
}
}
}
}
if ( (dwFlags & GCP_JUSTIFY) &&
( gcpwSave.lpDx ||
gcpwSave.lpCaretPos ) &&
nSet )
{
DPRINT1("We Need to Do Something HERE 2!\n");
}
if ( gcpwSave.lpDx && gcpwSave.lpCaretPos )
RtlCopyMemory( gcpwSave.lpCaretPos, gcpwSave.lpDx, nSet * sizeof(LONG));
if ( gcpwSave.lpCaretPos )
{
int pos = 0;
i = 0;
if ( nSet > 0 )
{
do
{
Cx = gcpwSave.lpCaretPos[i];
gcpwSave.lpCaretPos[i] = pos;
pos += Cx;
++i;
}
while ( i < nSet );
}
}
if ( gcpwSave.lpOutString )
RtlCopyMemory(gcpwSave.lpOutString, pwsz, nSet * sizeof(WCHAR));
if ( gcpwSave.lpClass )
RtlFillMemory(gcpwSave.lpClass, nSet, GCPCLASS_LATIN);
if ( gcpwSave.lpOrder )
{
for (i = 0; i < nSet; i++)
gcpwSave.lpOrder[i] = i;
}
if ( gcpwSave.lpGlyphs )
{
if ( GreGetGlyphIndicesW( hdc, pwsz, nSet, gcpwSave.lpGlyphs, 0, 0) == GDI_ERROR )
{
nSet = 0;
Size.cx = 0;
Size.cy = 0;
}
}
pgcpw->nGlyphs = nSet;
pgcpw->nMaxFit = nSet;
}
DPRINT1("GreGCPW Exit\n");
return MAKELONG(Size.cx, Size.cy);
}
#endif
ULONG
FASTCALL
FontGetObject(PTEXTOBJ plfont, ULONG cjBuffer, PVOID pvBuffer)
{
ULONG cjMaxSize;
ENUMLOGFONTEXDVW *plf = &plfont->logfont;
/* If buffer is NULL, only the size is requested */
if (pvBuffer == NULL) return sizeof(LOGFONTW);
/* Calculate the maximum size according to number of axes */
cjMaxSize = FIELD_OFFSET(ENUMLOGFONTEXDVW,
elfDesignVector.dvValues[plf->elfDesignVector.dvNumAxes]);
if (cjBuffer > cjMaxSize) cjBuffer = cjMaxSize;
RtlCopyMemory(pvBuffer, plf, cjBuffer);
return cjBuffer;
}
DWORD
FASTCALL
IntGetCharDimensions(HDC hdc, PTEXTMETRICW ptm, PDWORD height)
{
PDC pdc;
PDC_ATTR pdcattr;
PTEXTOBJ TextObj;
SIZE sz;
TMW_INTERNAL tmwi;
BOOL Good;
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(!ftGdiGetTextMetricsW(hdc, &tmwi)) return 0;
pdc = DC_LockDc(hdc);
if (!pdc) return 0;
pdcattr = pdc->pdcattr;
TextObj = RealizeFontInit(pdcattr->hlfntNew);
if ( !TextObj )
{
DC_UnlockDc(pdc);
return 0;
}
Good = TextIntGetTextExtentPoint(pdc, TextObj, alphabet, 52, 0, NULL, 0, &sz, 0);
TEXTOBJ_UnlockText(TextObj);
DC_UnlockDc(pdc);
if (!Good) return 0;
if (ptm) *ptm = tmwi.TextMetric;
if (height) *height = tmwi.TextMetric.tmHeight;
return (sz.cx / 26 + 1) / 2;
}
DWORD
FASTCALL
IntGetFontLanguageInfo(PDC Dc)
{
PDC_ATTR pdcattr;
FONTSIGNATURE fontsig;
static const DWORD GCP_DBCS_MASK=0x003F0000,
GCP_DIACRITIC_MASK=0x00000000,
FLI_GLYPHS_MASK=0x00000000,
GCP_GLYPHSHAPE_MASK=0x00000040,
GCP_KASHIDA_MASK=0x00000000,
GCP_LIGATE_MASK=0x00000000,
GCP_USEKERNING_MASK=0x00000000,
GCP_REORDER_MASK=0x00000060;
DWORD result=0;
ftGdiGetTextCharsetInfo( Dc, &fontsig, 0 );
/* We detect each flag we return using a bitmask on the Codepage Bitfields */
if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
result|=GCP_DBCS;
if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
result|=GCP_DIACRITIC;
if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
result|=FLI_GLYPHS;
if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
result|=GCP_GLYPHSHAPE;
if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
result|=GCP_KASHIDA;
if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
result|=GCP_LIGATE;
if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
result|=GCP_USEKERNING;
pdcattr = Dc->pdcattr;
/* This might need a test for a HEBREW- or ARABIC_CHARSET as well */
if ( pdcattr->lTextAlign & TA_RTLREADING )
if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
result|=GCP_REORDER;
return result;
}
PTEXTOBJ
FASTCALL
RealizeFontInit(HFONT hFont)
{
NTSTATUS Status = STATUS_SUCCESS;
PTEXTOBJ pTextObj;
pTextObj = TEXTOBJ_LockText(hFont);
if ( pTextObj && !(pTextObj->fl & TEXTOBJECT_INIT))
{
Status = TextIntRealizeFont(hFont, pTextObj);
if (!NT_SUCCESS(Status))
{
TEXTOBJ_UnlockText(pTextObj);
return NULL;
}
}
return pTextObj;
}
/** Functions ******************************************************************/
INT
APIENTRY
NtGdiAddFontResourceW(
IN WCHAR *pwcFiles,
IN ULONG cwc,
IN ULONG cFiles,
IN FLONG fl,
IN DWORD dwPidTid,
IN OPTIONAL DESIGNVECTOR *pdv)
{
UNICODE_STRING SafeFileName;
INT Ret;
DBG_UNREFERENCED_PARAMETER(cFiles);
DBG_UNREFERENCED_PARAMETER(dwPidTid);
DBG_UNREFERENCED_PARAMETER(pdv);
DPRINT("NtGdiAddFontResourceW\n");
/* cwc = Length + trailing zero. */
if (cwc <= 1 || cwc > UNICODE_STRING_MAX_CHARS)
return 0;
SafeFileName.MaximumLength = cwc * sizeof(WCHAR);
SafeFileName.Length = SafeFileName.MaximumLength - sizeof(UNICODE_NULL);
SafeFileName.Buffer = ExAllocatePoolWithTag(PagedPool,
SafeFileName.MaximumLength,
TAG_STRING);
if (!SafeFileName.Buffer)
{
return 0;
}
_SEH2_TRY
{
ProbeForRead(pwcFiles, cwc * sizeof(WCHAR), sizeof(WCHAR));
RtlCopyMemory(SafeFileName.Buffer, pwcFiles, SafeFileName.Length);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
_SEH2_YIELD(return 0);
}
_SEH2_END;
SafeFileName.Buffer[SafeFileName.Length / sizeof(WCHAR)] = UNICODE_NULL;
Ret = IntGdiAddFontResource(&SafeFileName, fl);
ExFreePoolWithTag(SafeFileName.Buffer, TAG_STRING);
return Ret;
}
HANDLE
APIENTRY
NtGdiAddFontMemResourceEx(
IN PVOID pvBuffer,
IN DWORD cjBuffer,
IN DESIGNVECTOR *pdv,
IN ULONG cjDV,
OUT DWORD *pNumFonts)
{
_SEH2_VOLATILE PVOID Buffer = NULL;
HANDLE Ret;
DWORD NumFonts = 0;
DPRINT("NtGdiAddFontMemResourceEx\n");
DBG_UNREFERENCED_PARAMETER(pdv);
DBG_UNREFERENCED_PARAMETER(cjDV);
if (!pvBuffer || !cjBuffer)
return NULL;
_SEH2_TRY
{
ProbeForRead(pvBuffer, cjBuffer, sizeof(BYTE));
Buffer = ExAllocatePoolWithQuotaTag(PagedPool, cjBuffer, TAG_FONT);
RtlCopyMemory(Buffer, pvBuffer, cjBuffer);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
if (Buffer != NULL)
{
ExFreePoolWithTag(Buffer, TAG_FONT);
}
_SEH2_YIELD(return NULL);
}
_SEH2_END;
Ret = IntGdiAddFontMemResource(Buffer, cjBuffer, &NumFonts);
ExFreePoolWithTag(Buffer, TAG_FONT);
_SEH2_TRY
{
ProbeForWrite(pNumFonts, sizeof(NumFonts), 1);
*pNumFonts = NumFonts;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Leak it? */
_SEH2_YIELD(return NULL);
}
_SEH2_END;
return Ret;
}
BOOL
APIENTRY
NtGdiRemoveFontMemResourceEx(
IN HANDLE hMMFont)
{
return IntGdiRemoveFontMemResource(hMMFont);
}
/*
* @unimplemented
*/
DWORD
APIENTRY
NtGdiGetCharacterPlacementW(
IN HDC hdc,
IN LPWSTR pwsz,
IN INT nCount,
IN INT nMaxExtent,
IN OUT LPGCP_RESULTSW pgcpw,
IN DWORD dwFlags)
{
UNIMPLEMENTED;
return 0;
#if 0
return GreGetCharacterPlacementW( hdc,
pwsz,
nCount,
nMaxExtent,
pgcpw,
dwFlags);
#endif
}
DWORD
APIENTRY
NtGdiGetFontData(
HDC hDC,
DWORD Table,
DWORD Offset,
LPVOID Buffer,
DWORD Size)
{
PDC Dc;
PDC_ATTR pdcattr;
HFONT hFont;
PTEXTOBJ TextObj;
PFONTGDI FontGdi;
DWORD Result = GDI_ERROR;
NTSTATUS Status = STATUS_SUCCESS;
if (Buffer && Size)
{
_SEH2_TRY
{
ProbeForRead(Buffer, Size, 1);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
}
if (!NT_SUCCESS(Status)) return Result;
Dc = DC_LockDc(hDC);
if (Dc == NULL)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return GDI_ERROR;
}
pdcattr = Dc->pdcattr;
hFont = pdcattr->hlfntNew;
TextObj = RealizeFontInit(hFont);
DC_UnlockDc(Dc);
if (TextObj == NULL)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return GDI_ERROR;
}
FontGdi = ObjToGDI(TextObj->Font, FONT);
Result = ftGdiGetFontData(FontGdi, Table, Offset, Buffer, Size);
TEXTOBJ_UnlockText(TextObj);
return Result;
}
/*
* @implemented
*/
DWORD
APIENTRY
NtGdiGetFontUnicodeRanges(
IN HDC hdc,
OUT OPTIONAL LPGLYPHSET pgs)
{
PDC pDc;
PDC_ATTR pdcattr;
HFONT hFont;
PTEXTOBJ TextObj;
PFONTGDI FontGdi;
DWORD Size = 0;
PGLYPHSET pgsSafe;
NTSTATUS Status = STATUS_SUCCESS;
pDc = DC_LockDc(hdc);
if (!pDc)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return 0;
}
pdcattr = pDc->pdcattr;
hFont = pdcattr->hlfntNew;
TextObj = RealizeFontInit(hFont);
if ( TextObj == NULL)
{
EngSetLastError(ERROR_INVALID_HANDLE);
goto Exit;
}
FontGdi = ObjToGDI(TextObj->Font, FONT);
Size = ftGetFontUnicodeRanges( FontGdi, NULL);
if (Size && pgs)
{
pgsSafe = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
if (!pgsSafe)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
Size = 0;
goto Exit;
}
Size = ftGetFontUnicodeRanges( FontGdi, pgsSafe);
if (Size)
{
_SEH2_TRY
{
ProbeForWrite(pgs, Size, 1);
RtlCopyMemory(pgs, pgsSafe, Size);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
if (!NT_SUCCESS(Status)) Size = 0;
}
ExFreePoolWithTag(pgsSafe, GDITAG_TEXT);
}
Exit:
TEXTOBJ_UnlockText(TextObj);
DC_UnlockDc(pDc);
return Size;
}
ULONG
APIENTRY
NtGdiGetGlyphOutline(
IN HDC hdc,
IN WCHAR wch,
IN UINT iFormat,
OUT LPGLYPHMETRICS pgm,
IN ULONG cjBuf,
OUT OPTIONAL PVOID UnsafeBuf,
IN LPMAT2 pmat2,
IN BOOL bIgnoreRotation)
{
ULONG Ret = GDI_ERROR;
PDC dc;
PVOID pvBuf = NULL;
GLYPHMETRICS gm;
NTSTATUS Status = STATUS_SUCCESS;
dc = DC_LockDc(hdc);
if (!dc)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return GDI_ERROR;
}
if (UnsafeBuf && cjBuf)
{
pvBuf = ExAllocatePoolWithTag(PagedPool, cjBuf, GDITAG_TEXT);
if (!pvBuf)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto Exit;
}
}
Ret = ftGdiGetGlyphOutline( dc,
wch,
iFormat,
pgm ? &gm : NULL,
cjBuf,
pvBuf,
pmat2,
bIgnoreRotation);
if (pvBuf)
{
_SEH2_TRY
{
ProbeForWrite(UnsafeBuf, cjBuf, 1);
RtlCopyMemory(UnsafeBuf, pvBuf, cjBuf);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
ExFreePoolWithTag(pvBuf, GDITAG_TEXT);
}
if (pgm)
{
_SEH2_TRY
{
ProbeForWrite(pgm, sizeof(GLYPHMETRICS), 1);
RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
}
if (! NT_SUCCESS(Status))
{
EngSetLastError(ERROR_INVALID_PARAMETER);
Ret = GDI_ERROR;
}
Exit:
DC_UnlockDc(dc);
return Ret;
}
DWORD
APIENTRY
NtGdiGetKerningPairs(HDC hDC,
ULONG NumPairs,
LPKERNINGPAIR krnpair)
{
PDC dc;
PDC_ATTR pdcattr;
PTEXTOBJ TextObj;
PFONTGDI FontGDI;
DWORD Count;
KERNINGPAIR *pKP;
NTSTATUS Status = STATUS_SUCCESS;
dc = DC_LockDc(hDC);
if (!dc)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return 0;
}
pdcattr = dc->pdcattr;
TextObj = RealizeFontInit(pdcattr->hlfntNew);
DC_UnlockDc(dc);
if (!TextObj)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return 0;
}
FontGDI = ObjToGDI(TextObj->Font, FONT);
TEXTOBJ_UnlockText(TextObj);
Count = ftGdiGetKerningPairs(FontGDI,0,NULL);
if ( Count && krnpair )
{
if (Count > NumPairs)
{
EngSetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
pKP = ExAllocatePoolWithTag(PagedPool, Count * sizeof(KERNINGPAIR), GDITAG_TEXT);
if (!pKP)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
ftGdiGetKerningPairs(FontGDI,Count,pKP);
_SEH2_TRY
{
ProbeForWrite(krnpair, Count * sizeof(KERNINGPAIR), 1);
RtlCopyMemory(krnpair, pKP, Count * sizeof(KERNINGPAIR));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
if (!NT_SUCCESS(Status))
{
EngSetLastError(ERROR_INVALID_PARAMETER);
Count = 0;
}
ExFreePoolWithTag(pKP,GDITAG_TEXT);
}
return Count;
}
/*
From "Undocumented Windows 2000 Secrets" Appendix B, Table B-2, page
472, this is NtGdiGetOutlineTextMetricsInternalW.
*/
ULONG
APIENTRY
NtGdiGetOutlineTextMetricsInternalW (HDC hDC,
ULONG Data,
OUTLINETEXTMETRICW *otm,
TMDIFF *Tmd)
{
PDC dc;
PDC_ATTR pdcattr;
PTEXTOBJ TextObj;
PFONTGDI FontGDI;
HFONT hFont = 0;
ULONG Size;
OUTLINETEXTMETRICW *potm;
NTSTATUS Status = STATUS_SUCCESS;
dc = DC_LockDc(hDC);
if (!dc)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return 0;
}
pdcattr = dc->pdcattr;
hFont = pdcattr->hlfntNew;
TextObj = RealizeFontInit(hFont);
DC_UnlockDc(dc);
if (!TextObj)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return 0;
}
FontGDI = ObjToGDI(TextObj->Font, FONT);
TextIntUpdateSize(dc, TextObj, FontGDI, TRUE);
TEXTOBJ_UnlockText(TextObj);
Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
if (!otm) return Size;
if (Size > Data)
{
EngSetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
if (!potm)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
IntGetOutlineTextMetrics(FontGDI, Size, potm);
if (otm)
{
_SEH2_TRY
{
ProbeForWrite(otm, Size, 1);
RtlCopyMemory(otm, potm, Size);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
if (!NT_SUCCESS(Status))
{
EngSetLastError(ERROR_INVALID_PARAMETER);
Size = 0;
}
}
ExFreePoolWithTag(potm,GDITAG_TEXT);
return Size;
}
W32KAPI
BOOL
APIENTRY
NtGdiGetFontResourceInfoInternalW(
IN LPWSTR pwszFiles,
IN ULONG cwc,
IN ULONG cFiles,
IN UINT cjIn,
IN OUT LPDWORD pdwBytes,
OUT LPVOID pvBuf,
IN DWORD dwType)
{
NTSTATUS Status = STATUS_SUCCESS;
DWORD dwBytes, dwBytesRequested;
UNICODE_STRING SafeFileNames;
BOOL bRet = FALSE;
ULONG cbStringSize;
LPVOID Buffer;
/* FIXME: Handle cFiles > 0 */
/* Check for valid dwType values */
if (dwType > 5)
{
EngSetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
/* Allocate a safe unicode string buffer */
cbStringSize = cwc * sizeof(WCHAR);
SafeFileNames.MaximumLength = SafeFileNames.Length = (USHORT)cbStringSize - sizeof(WCHAR);
SafeFileNames.Buffer = ExAllocatePoolWithTag(PagedPool,
cbStringSize,
TAG_USTR);
if (!SafeFileNames.Buffer)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
RtlZeroMemory(SafeFileNames.Buffer, SafeFileNames.MaximumLength);
/* Check buffers and copy pwszFiles to safe unicode string */
_SEH2_TRY
{
ProbeForRead(pwszFiles, cbStringSize, 1);
ProbeForWrite(pdwBytes, sizeof(DWORD), 1);
if (pvBuf)
ProbeForWrite(pvBuf, cjIn, 1);
dwBytes = *pdwBytes;
dwBytesRequested = dwBytes;
RtlCopyMemory(SafeFileNames.Buffer, pwszFiles, cbStringSize);
if (dwBytes > 0)
{
Buffer = ExAllocatePoolWithTag(PagedPool, dwBytes, TAG_FINF);
}
else
{
Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(DWORD), TAG_FINF);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
/* Free the string buffer for the safe filename */
ExFreePoolWithTag(SafeFileNames.Buffer, TAG_USTR);
return FALSE;
}
/* Do the actual call */
bRet = IntGdiGetFontResourceInfo(&SafeFileNames,
(pvBuf ? Buffer : NULL),
&dwBytes, dwType);
/* Check if succeeded */
if (bRet)
{
/* Copy the data back to caller */
_SEH2_TRY
{
/* Buffers are already probed */
if (pvBuf && dwBytesRequested > 0)
RtlCopyMemory(pvBuf, Buffer, min(dwBytesRequested, dwBytes));
*pdwBytes = dwBytes;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
bRet = FALSE;
}
}
ExFreePoolWithTag(Buffer, TAG_FINF);
/* Free the string for the safe filenames */
ExFreePoolWithTag(SafeFileNames.Buffer, TAG_USTR);
return bRet;
}
/*
* @unimplemented
*/
BOOL
APIENTRY
NtGdiGetRealizationInfo(
IN HDC hdc,
OUT PREALIZATION_INFO pri,
IN HFONT hf)
{
PDC pDc;
PTEXTOBJ pTextObj;
PFONTGDI pFontGdi;
PDC_ATTR pdcattr;
BOOL Ret = FALSE;
INT i = 0;
REALIZATION_INFO ri;
pDc = DC_LockDc(hdc);
if (!pDc)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return 0;
}
pdcattr = pDc->pdcattr;
pTextObj = RealizeFontInit(pdcattr->hlfntNew);
pFontGdi = ObjToGDI(pTextObj->Font, FONT);
TEXTOBJ_UnlockText(pTextObj);
DC_UnlockDc(pDc);
Ret = ftGdiRealizationInfo(pFontGdi, &ri);
if (Ret)
{
if (pri)
{
NTSTATUS Status = STATUS_SUCCESS;
_SEH2_TRY
{
ProbeForWrite(pri, sizeof(REALIZATION_INFO), 1);
RtlCopyMemory(pri, &ri, sizeof(REALIZATION_INFO));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
if(!NT_SUCCESS(Status))
{
SetLastNtError(Status);
return FALSE;
}
}
do
{
if (GdiHandleTable->cfPublic[i].hf == hf)
{
GdiHandleTable->cfPublic[i].iTechnology = ri.iTechnology;
GdiHandleTable->cfPublic[i].iUniq = ri.iUniq;
GdiHandleTable->cfPublic[i].dwUnknown = ri.dwUnknown;
GdiHandleTable->cfPublic[i].dwCFCount = GdiHandleTable->dwCFCount;
GdiHandleTable->cfPublic[i].fl |= CFONT_REALIZATION;
}
i++;
}
while ( i < GDI_CFONT_MAX );
}
return Ret;
}
HFONT
APIENTRY
HfontCreate(
IN PENUMLOGFONTEXDVW pelfw,
IN ULONG cjElfw,
IN LFTYPE lft,
IN FLONG fl,
IN PVOID pvCliData )
{
HFONT hNewFont;
PLFONT plfont;
if (!pelfw)
{
return NULL;
}
plfont = LFONT_AllocFontWithHandle();
if (!plfont)
{
return NULL;
}
hNewFont = plfont->BaseObject.hHmgr;
plfont->lft = lft;
plfont->fl = fl;
RtlCopyMemory (&plfont->logfont, pelfw, sizeof(ENUMLOGFONTEXDVW));
ExInitializePushLock(&plfont->lock);
if (pelfw->elfEnumLogfontEx.elfLogFont.lfEscapement !=
pelfw->elfEnumLogfontEx.elfLogFont.lfOrientation)
{
/* This should really depend on whether GM_ADVANCED is set */
plfont->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation =
plfont->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement;
}
LFONT_UnlockFont(plfont);
if (pvCliData && hNewFont)
{
// FIXME: Use GDIOBJ_InsertUserData
KeEnterCriticalRegion();
{
INT Index = GDI_HANDLE_GET_INDEX((HGDIOBJ)hNewFont);
PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
Entry->UserData = pvCliData;
}
KeLeaveCriticalRegion();
}
return hNewFont;
}
HFONT
APIENTRY
NtGdiHfontCreate(
IN PENUMLOGFONTEXDVW pelfw,
IN ULONG cjElfw,
IN LFTYPE lft,
IN FLONG fl,
IN PVOID pvCliData )
{
ENUMLOGFONTEXDVW SafeLogfont;
NTSTATUS Status = STATUS_SUCCESS;
/* Silence GCC warnings */
SafeLogfont.elfEnumLogfontEx.elfLogFont.lfEscapement = 0;
SafeLogfont.elfEnumLogfontEx.elfLogFont.lfOrientation = 0;
if (!pelfw)
{
return NULL;
}
_SEH2_TRY
{
ProbeForRead(pelfw, sizeof(ENUMLOGFONTEXDVW), 1);
RtlCopyMemory(&SafeLogfont, pelfw, sizeof(ENUMLOGFONTEXDVW));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
if (!NT_SUCCESS(Status))
{
return NULL;
}
return HfontCreate(&SafeLogfont, cjElfw, lft, fl, pvCliData);
}
/* EOF */