You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1243 lines
35 KiB
1243 lines
35 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: fdquery.c
|
|
*
|
|
* Contains all the vtfdQueryXXX functions. Adapted from BodinD's bitmap font
|
|
* driver.
|
|
*
|
|
* Copyright (c) 1990-1995 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "fd.h"
|
|
#include "exehdr.h"
|
|
|
|
#define OFF_CharWidth 2 //!!!Move to winfont.h
|
|
//!!!Define OFF_CharTable10
|
|
|
|
// Retrieve description string from .FON files.
|
|
|
|
BOOL bDescStr (PVOID pvView, SIZE_T cjView, PSZ pszString);
|
|
|
|
//
|
|
// Function prototypes.
|
|
//
|
|
|
|
ULONG
|
|
cjVtfdDeviceMetrics (
|
|
PFONTCONTEXT pfc,
|
|
FD_DEVICEMETRICS *pdevm
|
|
);
|
|
|
|
VOID
|
|
vFill_GlyphData (
|
|
PFONTCONTEXT pfc,
|
|
GLYPHDATA *pgldt,
|
|
UINT iIndex
|
|
);
|
|
|
|
BOOL
|
|
bCreatePath (
|
|
PCHAR pch,
|
|
PCHAR pchEnd,
|
|
PFONTCONTEXT pfc,
|
|
PATHOBJ *ppo,
|
|
FIX fxAB
|
|
);
|
|
|
|
VOID
|
|
vFill_GlyphData (
|
|
PFONTCONTEXT pfc,
|
|
GLYPHDATA *pgldt,
|
|
UINT iIndex
|
|
);
|
|
|
|
#if defined(_AMD64_) || defined(_IA64_)
|
|
#define lCvt(ef, l) ((LONG) (ef * l))
|
|
#else
|
|
LONG lCvt(EFLOAT ef,LONG l);
|
|
#endif
|
|
|
|
//!!! this function is living in ttfd. should be moved to the engine [bodind]
|
|
|
|
VOID vAddPOINTQF(POINTQF *, POINTQF *);
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL bReconnectVtfdFont(FONTFILE *pff)
|
|
*
|
|
*
|
|
* Effects: If the file is marked gone, we try to reconnect and see if we can
|
|
* use it again. We clear the exception bit so that the system will
|
|
* be able to use this font again.
|
|
*
|
|
* History:
|
|
* 17-Aug-1994 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
BOOL bReconnectVtfdFont(FONTFILE *pff)
|
|
{
|
|
INT i;
|
|
|
|
if ((pff->iType == TYPE_FNT) || (pff->iType == TYPE_DLL16))
|
|
{
|
|
|
|
if (!EngMapFontFileFD(pff->iFile, (PULONG*)&pff->pvView, &pff->cjView ))
|
|
{
|
|
WARNING("can not reconnect this vector font !!!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; i < (INT)pff->cFace; i++)
|
|
{
|
|
pff->afd[i].re.pvResData = (PVOID) (
|
|
(BYTE*)pff->pvView + pff->afd[i].re.dpResData
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// everything is fine again, clear the bit
|
|
|
|
pff->fl &= ~FF_EXCEPTION_IN_PAGE_ERROR;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* PIFIMETRICS vtfdQueryFont
|
|
*
|
|
* Return a pointer to the IFIMETRICS for the given face.
|
|
*
|
|
* History:
|
|
* 31-Aug-1992 Gilman Wong [gilmanw]
|
|
* IFI/DDI merge.
|
|
*
|
|
* 26-Feb-1992 -by- Wendy Wu [wendywu]
|
|
* Adapted from bmfd.
|
|
\**************************************************************************/
|
|
|
|
PIFIMETRICS vtfdQueryFont (
|
|
DHPDEV dhpdev,
|
|
HFF hff,
|
|
ULONG iFace,
|
|
ULONG_PTR *pid
|
|
)
|
|
{
|
|
PFONTFILE pff;
|
|
|
|
//
|
|
// Validate handle.
|
|
//
|
|
if (hff == HFF_INVALID)
|
|
{
|
|
WARNING("vtfdQueryFaces(): invalid iFile (hff)\n");
|
|
return (PIFIMETRICS) NULL;
|
|
}
|
|
|
|
//
|
|
// We never unlock FONTFILE since it contains IFIMETRICS that engine
|
|
// has a pointer to. hff is actually a pointer to the FONTFILE struct.
|
|
//
|
|
pff = (PFONTFILE)hff;
|
|
|
|
//
|
|
// Assume iFace within bounds.
|
|
//
|
|
ASSERTDD((iFace >= 1L) && (iFace <= pff->cFace),
|
|
"vtfdQueryFaces: iFace out of range\n");
|
|
|
|
//
|
|
// Return pointer to IFIMETRICS.
|
|
//
|
|
return pff->afd[iFace-1].pifi;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* LONG vtfdQueryFontCaps
|
|
*
|
|
* Retrieve the capabilities of the font driver.
|
|
*
|
|
* History:
|
|
* 26-Feb-1992 -by- Wendy Wu [wendywu]
|
|
* Adapted from bmfd.
|
|
\**************************************************************************/
|
|
|
|
LONG vtfdQueryFontCaps (
|
|
ULONG culCaps,
|
|
PULONG pulCaps
|
|
)
|
|
{
|
|
ASSERTDD(culCaps == 2, "ERROR - come on - update the font drivers");
|
|
pulCaps[0] = 2L;
|
|
|
|
//
|
|
// The vector font driver only returns outlines.
|
|
//
|
|
|
|
pulCaps[1] = QC_OUTLINES;
|
|
return(2);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vtfdQueryFontTree
|
|
*
|
|
* This function returns pointers to per-face information.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* dhpdev Not used.
|
|
*
|
|
* hff Handle to a font file.
|
|
*
|
|
* iFace Index of a face in the font file.
|
|
*
|
|
* iMode This is a 32-bit number that must be one of the following
|
|
* values:
|
|
*
|
|
* Allowed ulMode values:
|
|
* ----------------------
|
|
*
|
|
* QFT_LIGATURES -- returns a pointer to the ligature map.
|
|
*
|
|
* QFT_KERNPAIRS -- return a pointer to the kerning pair table.
|
|
*
|
|
* QFT_GLYPHSET -- return a pointer to the WC->HGLYPH mapping table.
|
|
*
|
|
* pid Not used.
|
|
*
|
|
* Returns:
|
|
a Returns a pointer to the requested data. This data will not change
|
|
* until VtfdfdFree is called on the pointer. Caller must not attempt to
|
|
* modify the data. NULL is returned if an error occurs.
|
|
*
|
|
* History:
|
|
* 31-Aug-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
PVOID
|
|
vtfdQueryFontTree (
|
|
DHPDEV dhpdev,
|
|
HFF hff,
|
|
ULONG iFace,
|
|
ULONG iMode,
|
|
ULONG_PTR *pid
|
|
)
|
|
{
|
|
PFONTFILE pff;
|
|
|
|
//
|
|
// Validate parameters.
|
|
//
|
|
if (hff == HFF_INVALID)
|
|
{
|
|
WARNING("vtfdQueryFontTree(): invalid iFile (hff)\n");
|
|
return ((PVOID) NULL);
|
|
}
|
|
|
|
//
|
|
// Convert from handle to pointer.
|
|
//
|
|
pff = (PFONTFILE)hff;
|
|
|
|
// Note: ulFont values are index-1 based.
|
|
|
|
if ((iFace < 1L) || (iFace > pff->cFace))
|
|
{
|
|
WARNING("vtfdQueryFontTree()\n");
|
|
return (NULL);
|
|
}
|
|
|
|
//
|
|
// Which mode?
|
|
//
|
|
switch (iMode)
|
|
{
|
|
case QFT_LIGATURES:
|
|
case QFT_KERNPAIRS:
|
|
|
|
//
|
|
// There are no ligatures or kerning pairs for the vector fonts,
|
|
// therefore we return NULL
|
|
//
|
|
return ((PVOID) NULL);
|
|
|
|
case QFT_GLYPHSET:
|
|
|
|
return &pff->afd[iFace - 1].pcp->gset;
|
|
|
|
default:
|
|
|
|
//
|
|
// Should never get here.
|
|
//
|
|
RIP("gdisrv!vtfdQueryFontTree(): unknown iMode\n");
|
|
return ((PVOID) NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vtfdQueryFontData
|
|
*
|
|
* dhpdev Not used.
|
|
*
|
|
* pfo Pointer to a FONTOBJ.
|
|
*
|
|
* iMode This is a 32-bit number that must be one of the following
|
|
* values:
|
|
*
|
|
* Allowed ulMode values:
|
|
* ----------------------
|
|
*
|
|
* QFD_GLYPH -- return glyph metrics only
|
|
*
|
|
* QFD_GLYPHANDBITMAP -- return glyph metrics and bitmap
|
|
*
|
|
* QFD_GLYPHANDOUTLINE -- return glyph metrics and outline
|
|
*
|
|
* QFD_MAXEXTENTS -- return FD_DEVICEMETRICS structure
|
|
*
|
|
* QFD_MAXGLYPHBITMAP -- return size of largest glyph AND its metrics
|
|
*
|
|
* cData Count of data items in the pvIn buffer.
|
|
*
|
|
* pvIn An array of glyph handles.
|
|
*
|
|
* pvOut Output buffer.
|
|
*
|
|
* Returns:
|
|
* If mode is QFD_MAXGLYPHBITMAP, then size of glyph metrics plus
|
|
* largest bitmap is returned.
|
|
*
|
|
* Otherwise, if pvOut is NULL, function will return size of the buffer
|
|
* needed to copy the data requested; else, the function will return the
|
|
* number of bytes written.
|
|
*
|
|
* FD_ERROR is returned if an error occurs.
|
|
*
|
|
* History:
|
|
* 31-Aug-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG
|
|
vtfdQueryFontData (
|
|
FONTOBJ *pfo,
|
|
ULONG iMode,
|
|
HGLYPH hg,
|
|
GLYPHDATA *pgd,
|
|
PVOID pv,
|
|
ULONG cjSize
|
|
)
|
|
{
|
|
PFONTCONTEXT pfc;
|
|
PBYTE ajHdr;
|
|
UINT iIndex, iIndexNext, offset1, offset2;
|
|
PCHAR pch, pchEnd;
|
|
PATHOBJ *ppo;
|
|
PBYTE pjFirstChar, ajCharTable;
|
|
GLYPHDATA gd;
|
|
|
|
// MAKE sure that the file is not gone
|
|
|
|
if (PFF(pfo->iFile)->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
{
|
|
// file gone, try to reconnect, if can not reconnect,
|
|
// no questions will be answered about it:
|
|
|
|
if (!bReconnectVtfdFont(PFF(pfo->iFile)))
|
|
{
|
|
WARNING("vtfdQueryFontData: EXCEPTION_IN_PAGE_ERROR\n");
|
|
return FD_ERROR;
|
|
}
|
|
}
|
|
|
|
// If pfo->pvProducer is NULL, then we need to open a font context.
|
|
|
|
if ( pfo->pvProducer == (PVOID) NULL )
|
|
pfo->pvProducer = (PVOID) vtfdOpenFontContext(pfo);
|
|
|
|
if ( pfo->pvProducer == (PVOID) NULL )
|
|
{
|
|
WARNING("vtfdQueryFontData: pvProducer\n");
|
|
return FD_ERROR;
|
|
}
|
|
|
|
pfc = (PFONTCONTEXT) pfo->pvProducer;
|
|
|
|
// Setup local pointers to font file header. Note that these
|
|
// could not be saved at fc creation time, for they could have changed
|
|
// after net went down and back up again after reconnecting. [bodind]
|
|
|
|
ajHdr = pfc->pre->pvResData;
|
|
pjFirstChar = ajHdr + pfc->dpFirstChar;
|
|
ajCharTable = ajHdr + OFF_jUnused20;
|
|
|
|
// What mode?
|
|
|
|
switch (iMode)
|
|
{
|
|
|
|
case QFD_GLYPHANDOUTLINE:
|
|
{
|
|
|
|
//
|
|
// Grab pointer to PATHOBJ* array.
|
|
//
|
|
ppo = (PATHOBJ *)pv;
|
|
|
|
|
|
//
|
|
// Assume the engine will not pass an invalid handle.
|
|
//
|
|
ASSERTDD(hg != HGLYPH_INVALID,
|
|
"vtfdQueryFontData(QFD_GLYPHANDOUTLINE): invalid hglyph\n");
|
|
|
|
//
|
|
// Use default glyph if hglyph out of range.
|
|
//
|
|
if (hg > (HGLYPH)(ajHdr[OFF_LastChar] - ajHdr[OFF_FirstChar]))
|
|
iIndex = ajHdr[OFF_DefaultChar];
|
|
else
|
|
iIndex = hg;
|
|
|
|
//
|
|
// Fill in the GLYPHDATA structure.
|
|
//
|
|
if( pgd == NULL )
|
|
{
|
|
pgd = &gd;
|
|
}
|
|
|
|
vFill_GlyphData(pfc, pgd, iIndex);
|
|
pgd->hg = hg;
|
|
|
|
//
|
|
// Construct the path.
|
|
//
|
|
if (ppo != NULL)
|
|
{
|
|
iIndexNext = iIndex + 1;
|
|
|
|
if (pfc->pifi->flInfo & FM_INFO_CONSTANT_WIDTH)
|
|
{
|
|
iIndex <<= 1; // each entry is 2-byte long
|
|
iIndexNext <<= 1;
|
|
}
|
|
else
|
|
{
|
|
iIndex <<= 2; // each entry is 4-byte long
|
|
iIndexNext <<= 2;
|
|
}
|
|
|
|
offset1 = READ_WORD(&ajCharTable[iIndex]);
|
|
offset2 = READ_WORD(&ajCharTable[iIndexNext]);
|
|
|
|
if ((offset2 < offset1) || (pfc->dpFirstChar + offset2 > pfc->pre->cjResData))
|
|
{
|
|
WARNING("vtfd!vtfdQueryFontData: offset to path out of file\n");
|
|
return FD_ERROR;
|
|
}
|
|
|
|
pch = pjFirstChar + offset1;
|
|
pchEnd = pjFirstChar + offset2;
|
|
|
|
ASSERTDD((*pch == PEN_UP),
|
|
"vtfdQueryFontData(QFD_GLYPHANDOUTLINE): First command is not PEN_UP");
|
|
|
|
if ( !bCreatePath(pch, pchEnd, pfc, ppo, pgd->fxAB) )
|
|
{
|
|
return FD_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return buffer size needed for all GLYPHDATA.
|
|
//
|
|
return 0;
|
|
|
|
case QFD_MAXEXTENTS:
|
|
//
|
|
// If buffer NULL, return size.
|
|
//
|
|
if ( pv == (PVOID) NULL )
|
|
return (sizeof(FD_DEVICEMETRICS));
|
|
|
|
//
|
|
// Otherwise, copy the data structure.
|
|
//
|
|
else
|
|
return cjVtfdDeviceMetrics(pfc, (FD_DEVICEMETRICS *) pv);
|
|
|
|
default:
|
|
|
|
WARNING("vtfdQueryFontData(): unsupported mode\n");
|
|
return FD_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vtfdQueryFontFile
|
|
*
|
|
* A function to query per font file information.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* hff Handle to a font file.
|
|
*
|
|
* ulMode This is a 32-bit number that must be one of the following
|
|
* values:
|
|
*
|
|
* Allowed ulMode values:
|
|
* ----------------------
|
|
*
|
|
* QFF_DESCRIPTION -- copies a UNICODE string in the buffer
|
|
* that describes the contents of the font file.
|
|
*
|
|
* QFF_NUMFACES -- returns number of faces in the font file.
|
|
*
|
|
* cjBuf Maximum number of BYTEs to copy into the buffer. The
|
|
* driver will not copy more than this many BYTEs.
|
|
*
|
|
* This should be zero if pulBuf is NULL.
|
|
*
|
|
* This parameter is not used in QFF_NUMFACES mode.
|
|
*
|
|
* pulBuf Pointer to the buffer to receive the data
|
|
* If this is NULL, then the required buffer size
|
|
* is returned as a count of BYTEs. Notice that this
|
|
* is a PULONG, to enforce 32-bit data alignment.
|
|
*
|
|
* This parameter is not used in QFF_NUMFACES mode.
|
|
*
|
|
* Returns:
|
|
*
|
|
* If mode is QFF_DESCRIPTION, then the number of BYTEs copied into
|
|
* the buffer is returned by the function. If pulBuf is NULL,
|
|
* then the required buffer size (as a count of BYTEs) is returned.
|
|
*
|
|
* If mode is QFF_NUMFACES, then number of faces in font file is returned.
|
|
*
|
|
* FD_ERROR is returned if an error occurs.
|
|
*
|
|
* History:
|
|
* 09-Mar-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG vtfdQueryFontFile (
|
|
HFF hff, // handle to font file
|
|
ULONG ulMode, // type of query
|
|
ULONG cjBuf, // size of buffer (in BYTEs)
|
|
PULONG pulBuf // return buffer (NULL if requesting size of data)
|
|
)
|
|
{
|
|
//
|
|
// We never unlock FONTFILE since it contains IFIMETRICS that the engine
|
|
// has a pointer to. hff is actually a pointer to the FONTFILE struct.
|
|
//
|
|
ULONG cjDescription;
|
|
PVOID pvView;
|
|
ULONG cjView;
|
|
PIFIMETRICS pifi;
|
|
LPWSTR pwszDescription;
|
|
|
|
ASSERTDD(hff, "vtfdQueryFontFile, hff invalid\n");
|
|
|
|
if (PFF(hff)->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
{
|
|
// file gone, try to reconnect, if can not reconnect,
|
|
// no questions will be answered about it:
|
|
|
|
if (!bReconnectVtfdFont(PFF(hff)))
|
|
{
|
|
WARNING("vtfdQueryFontFile: EXCEPTION_IN_PAGE_ERROR\n");
|
|
return FD_ERROR;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Which mode?
|
|
//
|
|
switch (ulMode)
|
|
{
|
|
case QFF_DESCRIPTION:
|
|
//
|
|
// If .FON format, retrieve the description string from the mapped file view.
|
|
//
|
|
if (PFF(hff)->iType == TYPE_DLL16)
|
|
{
|
|
CHAR achDescription[256]; // max length of string in the 16-bit EXE.
|
|
|
|
// check, maybe cRef is 0 so that fvw is not valid:
|
|
|
|
if (PFF(hff)->cRef == 0)
|
|
{
|
|
if (!EngMapFontFileFD(PFF(hff)->iFile,(PULONG*)&pvView,&cjView))
|
|
{
|
|
WARNING("somebody removed the file \n");
|
|
return FD_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pvView = PFF(hff)->pvView;
|
|
cjView = PFF(hff)->cjView;
|
|
}
|
|
|
|
cjDescription = FD_ERROR;
|
|
if (bDescStr(pvView, cjView, achDescription))
|
|
{
|
|
cjDescription = (strlen(achDescription) + 1) * sizeof(WCHAR);
|
|
|
|
//
|
|
// If there is a buffer, copy the data.
|
|
//
|
|
if ( pulBuf != (PULONG) NULL )
|
|
{
|
|
//
|
|
// Is buffer big enough?
|
|
//
|
|
if ( cjBuf < cjDescription )
|
|
{
|
|
WARNING("vtfdQueryFontFile(): buffer too small for string\n");
|
|
return (FD_ERROR);
|
|
}
|
|
else
|
|
{
|
|
vToUNICODEN((LPWSTR)pulBuf, cjDescription/sizeof(WCHAR), achDescription, cjDescription/sizeof(WCHAR));
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// clean up if need be
|
|
|
|
if (PFF(hff)->cRef == 0)
|
|
EngUnmapFontFileFD(PFF(hff)->iFile);
|
|
|
|
return(cjDescription);
|
|
}
|
|
|
|
//
|
|
// Otherwise, .FNT files do not have a description string. We may also
|
|
// get here if its a .FON format but bDescStr failed. We will have
|
|
// to use the facename.
|
|
//
|
|
|
|
//
|
|
// Get ptr to the facename in the IFIMETRICS of the first font
|
|
// in this font file.
|
|
//
|
|
pifi = PFF(hff)->afd[0].pifi;
|
|
pwszDescription = (LPWSTR)((PBYTE) pifi + pifi->dpwszFaceName);
|
|
cjDescription = (wcslen(pwszDescription) + 1) * sizeof(WCHAR);
|
|
|
|
//
|
|
// If there is a buffer, copy to it.
|
|
//
|
|
if ( pulBuf != (PULONG) NULL )
|
|
{
|
|
//
|
|
// Is buffer big enough?
|
|
//
|
|
if ( cjBuf < cjDescription )
|
|
{
|
|
WARNING("vtfdQueryFontFile(): buffer too small for face\n");
|
|
return (FD_ERROR);
|
|
}
|
|
else
|
|
{
|
|
RtlCopyMemory((PVOID) pulBuf,
|
|
(PVOID) pwszDescription,
|
|
cjDescription);
|
|
}
|
|
}
|
|
|
|
return(cjDescription);
|
|
|
|
case QFF_NUMFACES:
|
|
|
|
return PFF(hff)->cFace;
|
|
|
|
default:
|
|
WARNING("vtfdQueryFontFile(): unknown mode\n");
|
|
break;
|
|
}
|
|
|
|
// Default return. We should not get here.
|
|
return FD_ERROR;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* cjVtfdDeviceMetrics
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* History:
|
|
* 30-Aug-1992 -by- Gilman Wong [gilmanw]
|
|
* Stole it from WendyWu's FdQueryFaceAttr() implementation.
|
|
\**************************************************************************/
|
|
|
|
ULONG
|
|
cjVtfdDeviceMetrics (
|
|
PFONTCONTEXT pfc,
|
|
FD_DEVICEMETRICS *pdevm
|
|
)
|
|
{
|
|
PIFIMETRICS pifi;
|
|
EFLOAT efM11, efM12, efM21, efM22;
|
|
BOOL bScaleOnly;
|
|
|
|
// Compute the accelerator flags for this font.
|
|
|
|
pdevm->flRealizedType = 0; // no bitmaps are produced
|
|
|
|
if ((pfc->flags & FC_SIM_ITALICIZE) == 0)
|
|
pdevm->flRealizedType |= FDM_TYPE_ZERO_BEARINGS;
|
|
|
|
// Make sure nobody updates the font context when we're reading from it.
|
|
// !!! not possible, ResetFontContext is gone, [BODIND]
|
|
|
|
efM11 = pfc->efM11;
|
|
efM12 = pfc->efM12;
|
|
efM21 = pfc->efM21;
|
|
efM22 = pfc->efM22;
|
|
|
|
pdevm->pteBase = pfc->pteUnitBase;
|
|
pdevm->pteSide = pfc->pteUnitSide;
|
|
|
|
// fxMaxAscender/Descender are the distance from the baseline to the
|
|
// top/bottom of the glyph. fxInkTop/Bottom are vectors along the
|
|
// ascent direction. We need to adjust the sign properly.
|
|
|
|
pdevm->fxMaxAscender = pfc->fxInkTop;
|
|
pdevm->fxMaxDescender = -pfc->fxInkBottom;
|
|
|
|
bScaleOnly = pfc->flags & FC_SCALE_ONLY;
|
|
|
|
pdevm->cxMax = (ULONG)
|
|
((fxLTimesEf(&pfc->efBase, (LONG)pfc->pifi->fwdMaxCharInc) + 8) >> 4);
|
|
|
|
// Transform the character increment vector.
|
|
|
|
if
|
|
(
|
|
// only report accellerators for horiz case
|
|
|
|
(pfc->pifi->flInfo & FM_INFO_CONSTANT_WIDTH) &&
|
|
(pfc->flags & FC_SCALE_ONLY)
|
|
)
|
|
{
|
|
pdevm->lD = (LONG)pdevm->cxMax;
|
|
}
|
|
else // var pitch
|
|
{
|
|
pdevm->lD = 0;
|
|
}
|
|
|
|
// Transform the StrikeOut and Underline vectors.
|
|
|
|
pifi = pfc->pifi;
|
|
pdevm->ptlUnderline1.y = FXTOLROUND(fxLTimesEf(&efM22, -pifi->fwdUnderscorePosition));
|
|
pdevm->ptlStrikeOut.y = FXTOLROUND(fxLTimesEf(&efM22, -pifi->fwdStrikeoutPosition));
|
|
|
|
pdevm->ptlULThickness.y = pdevm->ptlSOThickness.y = 1;
|
|
pdevm->ptlULThickness.x = pdevm->ptlSOThickness.x = 0;
|
|
|
|
if (pfc->flags & FC_SIM_EMBOLDEN)
|
|
pdevm->ptlULThickness.y = pdevm->ptlSOThickness.y = 2;
|
|
|
|
if (bScaleOnly)
|
|
{
|
|
pdevm->ptlUnderline1.x = pdevm->ptlStrikeOut.x = 0;
|
|
|
|
if (!bPositive(efM22))
|
|
{
|
|
pdevm->ptlULThickness.y = -pdevm->ptlULThickness.y;
|
|
pdevm->ptlSOThickness.y = -pdevm->ptlSOThickness.y;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// !!!Cache this in HDC if underline or strikeout are used often.
|
|
|
|
pdevm->ptlULThickness.x = FXTOLROUND(fxLTimesEf(&efM21, pdevm->ptlULThickness.y));
|
|
pdevm->ptlULThickness.y = FXTOLROUND(fxLTimesEf(&efM22, pdevm->ptlULThickness.y));
|
|
pdevm->ptlSOThickness.x = pdevm->ptlULThickness.x;
|
|
pdevm->ptlSOThickness.y = pdevm->ptlULThickness.y;
|
|
|
|
pdevm->ptlUnderline1.x = FXTOLROUND(fxLTimesEf(&efM21, -pifi->fwdUnderscorePosition));
|
|
pdevm->ptlStrikeOut.x = FXTOLROUND(fxLTimesEf(&efM21, -pifi->fwdStrikeoutPosition));
|
|
}
|
|
|
|
// devm, no bitmaps are supported;
|
|
|
|
pdevm->cyMax = 0;
|
|
pdevm->cjGlyphMax = 0;
|
|
|
|
return(sizeof(FD_DEVICEMETRICS));
|
|
}
|
|
|
|
|
|
/******************************Private*Routine*****************************\
|
|
* VOID vFill_GlyphData
|
|
*
|
|
* Fill in the GLYPHDATA structure for the given glyph index.
|
|
*
|
|
* History:
|
|
* 18-Feb-1992 -by- Wendy Wu [wendywu]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vFill_GlyphData(PFONTCONTEXT pfc, GLYPHDATA *pgldt, UINT iIndex)
|
|
{
|
|
LONG lCharInc;
|
|
PBYTE ajCharTable = (PBYTE)pfc->pre->pvResData + OFF_jUnused20;
|
|
|
|
pgldt->gdf.pgb = NULL;
|
|
pgldt->hg = iIndex; //!!!????
|
|
|
|
// Transform the character increment vector.
|
|
|
|
if (pfc->pifi->flInfo & FM_INFO_CONSTANT_WIDTH)
|
|
{
|
|
lCharInc = pfc->pifi->fwdMaxCharInc;
|
|
}
|
|
else
|
|
{
|
|
// We're dealing with variable-width font, get the width from
|
|
// the chartable. Each entry in CharTable is 4-byte long.
|
|
|
|
lCharInc = READ_WORD(ajCharTable + OFF_CharWidth + (iIndex << 2));
|
|
}
|
|
|
|
pgldt->fxInkTop = pfc->fxInkTop;
|
|
pgldt->fxInkBottom = pfc->fxInkBottom;
|
|
|
|
if (pfc->flags & FC_SCALE_ONLY)
|
|
{
|
|
// here we do rounding to be compat with windows 31, and also to
|
|
// so that we can report the accelerator pdevm->lD for fixed pitch
|
|
// font as being really equal to fxD's for such a font
|
|
|
|
pgldt->fxD = ((fxLTimesEf(&pfc->efBase, lCharInc) + 8) & 0xfffffff0);
|
|
|
|
// Simple scaling transform.
|
|
|
|
if (pfc->flags & FC_X_INVERT)
|
|
pgldt->ptqD.x.HighPart = -pgldt->fxD;
|
|
else
|
|
pgldt->ptqD.x.HighPart = pgldt->fxD;
|
|
|
|
pgldt->ptqD.x.LowPart = 0;
|
|
pgldt->ptqD.y.HighPart = 0;
|
|
pgldt->ptqD.y.LowPart = 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
// in this case we do not do rounding, we want everything consistent:
|
|
|
|
pgldt->fxD = fxLTimesEf(&pfc->efBase, lCharInc);
|
|
|
|
// Non trivial transform.
|
|
|
|
vLTimesVtfl(lCharInc, &pfc->vtflBase, &pgldt->ptqD);
|
|
}
|
|
|
|
//!!! not sure if these should be calculated differently for non-trivial cases.
|
|
|
|
pgldt->fxA = 0;
|
|
pgldt->fxAB = pgldt->fxD;
|
|
|
|
if (pfc->flags & FC_SIM_EMBOLDEN)
|
|
{
|
|
pgldt->fxAB += pfc->fxEmbolden;
|
|
}
|
|
|
|
if (pfc->flags & FC_SIM_ITALICIZE)
|
|
{
|
|
pgldt->fxAB += pfc->fxItalic;
|
|
}
|
|
|
|
//!!! rclInk is missing, but not needed I guess (bodind)
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vtfdQueryAdvanceWidths *
|
|
* *
|
|
* A routine to compute advance widths. *
|
|
* *
|
|
* History: *
|
|
* Mon 18-Jan-1993 08:13:02 -by- Charles Whitmer [chuckwh] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
BOOL vtfdQueryAdvanceWidths
|
|
(
|
|
FONTOBJ *pfo,
|
|
ULONG iMode,
|
|
HGLYPH *phg,
|
|
LONG *plWidths,
|
|
ULONG cGlyphs
|
|
)
|
|
{
|
|
FONTCONTEXT *pfc;
|
|
USHORT *psWidths = (USHORT *) plWidths; // True for the cases we handle.
|
|
LONG dx;
|
|
ULONG ii;
|
|
PBYTE ajCharTable;
|
|
|
|
if (PFF(pfo->iFile)->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
{
|
|
// file gone, try to reconnect, if can not reconnect,
|
|
// no questions will be answered about it:
|
|
|
|
if (!bReconnectVtfdFont(PFF(pfo->iFile)))
|
|
{
|
|
WARNING("vtfdQueryAdvanceWidths: EXCEPTION_IN_PAGE_ERROR\n");
|
|
return FD_ERROR;
|
|
}
|
|
}
|
|
|
|
// If pfo->pvProducer is NULL, then we need to open a font context.
|
|
|
|
if ( pfo->pvProducer == (PVOID) NULL )
|
|
pfo->pvProducer = (PVOID) vtfdOpenFontContext(pfo);
|
|
|
|
if ( pfo->pvProducer == (PVOID) NULL )
|
|
{
|
|
WARNING("vtfdQueryAdvanceWidths: pvProducer\n");
|
|
return FD_ERROR;
|
|
}
|
|
|
|
pfc = (FONTCONTEXT *) pfo->pvProducer;
|
|
ajCharTable = (PBYTE)pfc->pre->pvResData + OFF_jUnused20;
|
|
|
|
ASSERTDD(!(pfc->pifi->flInfo & FM_INFO_CONSTANT_WIDTH),
|
|
"this is a fixed pitch font\n");
|
|
|
|
// only report accellerators
|
|
|
|
ASSERTDD((pfc->flags & FC_SCALE_ONLY),
|
|
"must not be a rotating xform\n");
|
|
|
|
// Get the widths.
|
|
|
|
for (ii=0; ii<cGlyphs; ii++,phg++,psWidths++)
|
|
{
|
|
dx = READ_WORD(ajCharTable + OFF_CharWidth + (*phg << 2));
|
|
*psWidths = (SHORT) ((lCvt(pfc->efBase,dx) + 8) & 0xfffffff0);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/******************************Private*Routine*****************************\
|
|
* BOOL bCreatePath
|
|
*
|
|
* Create a path by reading the vector descriptions contained in the
|
|
* memory space pointed to between pch and pchEnd.
|
|
*
|
|
* History:
|
|
* 18-Feb-1992 -by- Wendy Wu [wendywu]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#define CPTS_MAX 5
|
|
|
|
BOOL
|
|
bCreatePath(
|
|
PCHAR pch,
|
|
PCHAR pchEnd,
|
|
PFONTCONTEXT pfc,
|
|
PATHOBJ *ppo,
|
|
FIX fxAB)
|
|
{
|
|
UINT iPt, cPts = 0;
|
|
LONG lXLast, lDesc;
|
|
POINTL aptl[CPTS_MAX];
|
|
POINTFIX aptfx[CPTS_MAX];
|
|
BOOL bEmbolden, bItalicize, bScaleOnly, bReturn = TRUE;
|
|
EFLOAT efM11, efM12, efM21, efM22;
|
|
POINTFIX pfxBaseOffset;
|
|
POINTFIX ptfxBound;
|
|
|
|
efM11 = pfc->efM11;
|
|
efM12 = pfc->efM12;
|
|
efM21 = pfc->efM21;
|
|
efM22 = pfc->efM22;
|
|
|
|
|
|
lDesc = pfc->pifi->fwdWinDescender;
|
|
bEmbolden = pfc->flags & FC_SIM_EMBOLDEN;
|
|
bItalicize = pfc->flags & FC_SIM_ITALICIZE;
|
|
bScaleOnly = pfc->flags & FC_SCALE_ONLY;
|
|
|
|
pfxBaseOffset = pfc->pfxBaseOffset;
|
|
|
|
|
|
// Some points in the glyphs paths may end up on the bottom or right edge of
|
|
// the bounding rectangle for a glyph. Because of GIQ it is possible that
|
|
// sometimes these pels will get lit. However, because our bounding rectangles
|
|
// are bottom right exclusive they will never be considered to contain these
|
|
// pels. This is a problem. We need to adjust by making sure that any points
|
|
// which can possibly light a pel on the bottom or right edge of the bounding
|
|
// rectangle are adjust either to the right or up. Note that we only need
|
|
// to worry about orientations of 90 degrees because the engine will relax
|
|
// the bouding rectangle by one pel at other orientations. There are 8 cases
|
|
// altogether when we take flipping into account. [gerritv]
|
|
|
|
|
|
switch( pfc->flags & ORIENT_MASK )
|
|
{
|
|
case FC_ORIENT_1:
|
|
ptfxBound.x = fxAB - 0x10;
|
|
ptfxBound.y = -pfc->fxInkBottom - 0x10;
|
|
break;
|
|
case FC_ORIENT_2:
|
|
ptfxBound.x = fxAB - 0x10;
|
|
ptfxBound.y = pfc->fxInkTop - 0x10;
|
|
break;
|
|
case FC_ORIENT_3:
|
|
ptfxBound.y = pfc->fxInkTop - 0x10;
|
|
ptfxBound.x = -0x10;
|
|
break;
|
|
case FC_ORIENT_4:
|
|
ptfxBound.y = -pfc->fxInkBottom - 0x10;
|
|
ptfxBound.x = -0x10;
|
|
break;
|
|
case FC_ORIENT_5:
|
|
ptfxBound.x = -pfc->fxInkBottom - 0x10;
|
|
ptfxBound.y = fxAB - 0x10;
|
|
break;
|
|
case FC_ORIENT_6:
|
|
ptfxBound.x = -pfc->fxInkBottom - 0x10;
|
|
ptfxBound.y = -0x10;
|
|
break;
|
|
case FC_ORIENT_7:
|
|
ptfxBound.x = pfc->fxInkTop - 0x10;
|
|
ptfxBound.y = fxAB - 0x10;
|
|
break;
|
|
case FC_ORIENT_8:
|
|
ptfxBound.y = -0x10;
|
|
ptfxBound.x = pfc->fxInkTop - 0x10;
|
|
break;
|
|
}
|
|
|
|
|
|
// The path starts from the top left corner of the cell.
|
|
|
|
aptl[0].y = -pfc->pifi->fwdWinAscender;
|
|
|
|
aptl[0].x = 0;
|
|
|
|
while(pch <= pchEnd)
|
|
{
|
|
if ( (pch != pchEnd) && (*pch != PEN_UP))
|
|
{
|
|
// Check if there is space left. If not, send this batch of points
|
|
// to engine for path construction.
|
|
|
|
if (cPts >= CPTS_MAX)
|
|
goto BUILD_PATH;
|
|
|
|
// Attach this point to the end of the pointl array.
|
|
|
|
// claudebe, NTRAID#440755 and 440756, PREFIX, we could have cPts == 0 and accessing
|
|
// aptl[-1], since vector font are becoming obsolete and this is very old code
|
|
// and no customer ever complain about a problem getting the path of a vector font
|
|
// I'm just doing a minimal fix to prevent accessing aptl[-1]
|
|
if (cPts > 0)
|
|
{
|
|
aptl[cPts].x = (signed char)*pch++ + aptl[cPts-1].x;
|
|
if (pch == pchEnd)
|
|
{
|
|
WARNING("vtfd!bCreatePath(): y coordinate out of font file\n");
|
|
return FALSE;
|
|
}
|
|
aptl[cPts].y = (signed char)*pch++ + aptl[cPts-1].y;
|
|
} else {
|
|
aptl[cPts].x = (signed char)*pch++ ;
|
|
if (pch == pchEnd)
|
|
{
|
|
WARNING("vtfd!bCreatePath(): y coordinate out of font file\n");
|
|
return FALSE;
|
|
}
|
|
aptl[cPts].y = (signed char)*pch++ ;
|
|
}
|
|
|
|
cPts++;
|
|
|
|
}
|
|
else
|
|
{
|
|
if (cPts > 1)
|
|
{
|
|
BUILD_PATH:
|
|
|
|
cPts--;
|
|
|
|
// If Italic simulation is asked, x coordinates of all the points
|
|
// will be changed. Save the x of the last point so the next
|
|
// batch will have a correct reference point.
|
|
|
|
lXLast = aptl[cPts].x;
|
|
#if DEBUG
|
|
{
|
|
UINT i;
|
|
DbgPrint("MoveTo (%lx, %lx)\n", aptl[0].x, aptl[0].y);
|
|
DbgPrint("PolyLineTo cPts = %lx\n",cPts);
|
|
for (i = 1; i <= cPts; i++)
|
|
{
|
|
DbgPrint(" (%lx, %lx)\n",aptl[i].x, aptl[i].y);
|
|
}
|
|
}
|
|
#endif
|
|
if (bItalicize)
|
|
{
|
|
for (iPt = 0; iPt <= cPts; iPt++)
|
|
aptl[iPt].x += (lDesc - aptl[iPt].y)>>1;
|
|
}
|
|
|
|
if (bScaleOnly)
|
|
{
|
|
for (iPt = 0; iPt <= cPts; iPt++)
|
|
{
|
|
aptfx[iPt].x = (FIX)lCvt(efM11, aptl[iPt].x);
|
|
aptfx[iPt].y = (FIX)lCvt(efM22, aptl[iPt].y);
|
|
|
|
|
|
if( aptfx[iPt].y > ptfxBound.y )
|
|
{
|
|
#if DEBUG
|
|
DbgPrint("y adjust %x to %x\n", aptfx[iPt].y, ptfxBound.y );
|
|
#endif
|
|
aptfx[iPt].y = ptfxBound.y;
|
|
}
|
|
|
|
if( aptfx[iPt].x > ptfxBound.x )
|
|
{
|
|
#if DEBUG
|
|
DbgPrint("x adjust %x %x\n", aptfx[iPt].x, ptfxBound.x );
|
|
#endif
|
|
aptfx[iPt].x = ptfxBound.x;
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (iPt = 0; iPt <= cPts; iPt++)
|
|
{
|
|
aptfx[iPt].x = (FIX)lCvt(efM11, aptl[iPt].x) +
|
|
(FIX)lCvt(efM21, aptl[iPt].y);
|
|
aptfx[iPt].y = (FIX)lCvt(efM12, aptl[iPt].x) +
|
|
(FIX)lCvt(efM22, aptl[iPt].y);
|
|
|
|
// only if an orientation flag is set then we must adjust
|
|
|
|
if( pfc->flags & ORIENT_MASK )
|
|
{
|
|
|
|
if( aptfx[iPt].y > ptfxBound.y )
|
|
{
|
|
#if DEBUG
|
|
DbgPrint("y adjust %x %x\n", aptfx[iPt].y, ptfxBound.y );
|
|
#endif
|
|
aptfx[iPt].y = ptfxBound.y;
|
|
}
|
|
|
|
|
|
if( aptfx[iPt].x > ptfxBound.x )
|
|
{
|
|
#if DEBUG
|
|
DbgPrint("x adjust %x %x\n", aptfx[iPt].x, ptfxBound.x );
|
|
#endif
|
|
aptfx[iPt].x = ptfxBound.x;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bReturn &= PATHOBJ_bMoveTo(ppo, aptfx[0]);
|
|
bReturn &= PATHOBJ_bPolyLineTo(ppo, &aptfx[1], cPts);
|
|
#if DEBUG
|
|
{
|
|
UINT i;
|
|
DbgPrint("MoveTo (%lx, %lx)\n", aptfx[0].x, aptfx[0].y);
|
|
DbgPrint("PolyLineTo cPts = %lx\n",cPts);
|
|
for (i = 1; i <= cPts; i++)
|
|
{
|
|
DbgPrint(" (%lx, %lx)\n",aptfx[i].x, aptfx[i].y);
|
|
}
|
|
}
|
|
#endif
|
|
if (bEmbolden)
|
|
{
|
|
for (iPt = 0; iPt <= cPts; iPt++)
|
|
{
|
|
// offset the whole path in the unit base direction
|
|
|
|
aptfx[iPt].x += pfxBaseOffset.x;
|
|
aptfx[iPt].y += pfxBaseOffset.y;
|
|
}
|
|
|
|
bReturn &= PATHOBJ_bMoveTo(ppo, aptfx[0]);
|
|
bReturn &= PATHOBJ_bPolyLineTo(ppo, &aptfx[1], cPts);
|
|
}
|
|
|
|
if ((pch != pchEnd) && (*pch != PEN_UP) )
|
|
{
|
|
// We got here because the aptl[] and aptfx[] buffer is
|
|
// not big enough. Move to the last point in PolyLineTo
|
|
// and start storing the next batch of points.
|
|
|
|
aptl[0].x = lXLast;
|
|
aptl[0].y = aptl[cPts].y;
|
|
cPts = 1;
|
|
continue;
|
|
}
|
|
|
|
aptl[cPts].x = lXLast;
|
|
}
|
|
|
|
pch++;
|
|
if (pch == pchEnd)
|
|
{
|
|
WARNING("vtfd!bCreatePath(): final x coordinate out of font file\n");
|
|
return FALSE;
|
|
}
|
|
|
|
aptl[0].x = (signed char)*pch++ + aptl[cPts].x;
|
|
if (pch == pchEnd)
|
|
{
|
|
WARNING("vtfd!bCreatePath(): final y coordinate out of font file\n");
|
|
return FALSE;
|
|
}
|
|
aptl[0].y = (signed char)*pch++ + aptl[cPts].y;
|
|
cPts = 1;
|
|
}
|
|
}
|
|
|
|
return(bReturn);
|
|
}
|