mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 00:45:24 +00:00

Separate TextOut for internal use. Use flTextAlign internally. Not sure why GetDeviceCap was used for determining rendering. SVN commit logs are unavailable. Include code from wine that might make more sense.
1228 lines
28 KiB
C
1228 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;
|
|
DPRINT1("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 = 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);
|
|
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 */
|