mirror of
https://github.com/reactos/reactos.git
synced 2024-08-28 22:28:36 +00:00
1234 lines
28 KiB
C
1234 lines
28 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.
|
|
|
|
MS 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;
|
|
|
|
ASSERT(plfont);
|
|
plf = &plfont->logfont;
|
|
|
|
if (!(plfont->fl & TEXTOBJECT_INIT))
|
|
{
|
|
NTSTATUS Status;
|
|
DPRINT("FontGetObject font not initialized!\n");
|
|
|
|
Status = TextIntRealizeFont(plfont->BaseObject.hHmgr, plfont);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DPRINT1("FontGetObject(TextIntRealizeFont) Status = 0x%lx\n", Status);
|
|
}
|
|
}
|
|
|
|
/* 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->flTextAlign & 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 = (USHORT)(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 = ExAllocatePoolZero(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);
|
|
if (!(FontGDI->flType & FO_TYPE_TRUETYPE))
|
|
{
|
|
TEXTOBJ_UnlockText(TextObj);
|
|
return 0;
|
|
}
|
|
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;
|
|
}
|
|
RtlZeroMemory(potm, Size);
|
|
IntGetOutlineTextMetrics(FontGDI, Size, potm);
|
|
|
|
_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);
|
|
ASSERT(pTextObj != NULL);
|
|
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 */
|