mirror of https://github.com/lianthony/NT4.0
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.
2540 lines
76 KiB
2540 lines
76 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: fdfc.c *
|
|
* *
|
|
* Open,Close,Reset Font Context *
|
|
* *
|
|
* Created: 18-Nov-1991 11:55:38 *
|
|
* Author: Bodin Dresevic [BodinD] *
|
|
* *
|
|
* Copyright (c) 1993 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
|
|
#include "fd.h"
|
|
#include "winfont.h"
|
|
|
|
#if DBG
|
|
// #define DBG_XFORM
|
|
extern ULONG gflTtfdDebug;
|
|
ULONG gflTtfdDebug = 0;
|
|
#endif
|
|
|
|
BOOL bSetXform
|
|
(
|
|
PFONTCONTEXT pfc // OUT
|
|
);
|
|
|
|
STATIC BOOL bNewXform
|
|
(
|
|
FONTOBJ *pfo, // IN
|
|
PFONTCONTEXT pfc // OUT
|
|
);
|
|
|
|
|
|
STATIC BOOL bComputeMaxGlyph(PFONTCONTEXT pfc);
|
|
|
|
#define CVT_TRUNCATE 0x00000001
|
|
#define CVT_TO_FIX 0X00000002
|
|
|
|
STATIC BOOL bFloatToL(FLOAT e, PLONG pl);
|
|
STATIC Fixed fxPtSize(PFONTCONTEXT pfc);
|
|
STATIC BOOL ttfdCloseFontContext(FONTCONTEXT *pfc);
|
|
STATIC VOID vFindHdmxTable(PFONTCONTEXT pfc);
|
|
STATIC ULONG iHipot(LONG x, LONG y);
|
|
LONG lFFF(LONG l);
|
|
#define FFF(e,l) *(LONG*)(&(e)) = lFFF(l)
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL bInitInAndOut
|
|
*
|
|
*
|
|
* History:
|
|
* 18-Nov-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
BOOL bInitInAndOut(FONTFILE *pff)
|
|
{
|
|
FS_ENTRY iRet;
|
|
fs_GlyphInputType *pgin;
|
|
fs_GlyphInfoType *pgout;
|
|
|
|
ASSERTDD(pff->pj034 != NULL, "pff->pj3 IS null\n");
|
|
|
|
pgin = (fs_GlyphInputType *)pff->pj034;
|
|
pgout = (fs_GlyphInfoType *)(pff->pj034 + CJ_IN);
|
|
|
|
if ((iRet = fs_OpenFonts(pgin, pgout)) != NO_ERR)
|
|
{
|
|
V_FSERROR(iRet);
|
|
return (FALSE);
|
|
}
|
|
|
|
pgin->memoryBases[0] = (char *)(pff->pj034 + CJ_IN + CJ_OUT);
|
|
pgin->memoryBases[1] = NULL;
|
|
pgin->memoryBases[2] = NULL;
|
|
|
|
// initialize the font scaler, notice no fields of pfc->gin are initialized [BodinD]
|
|
|
|
if ((iRet = fs_Initialize(pgin, pgout)) != NO_ERR)
|
|
{
|
|
// clean up and return:
|
|
|
|
V_FSERROR(iRet);
|
|
RET_FALSE("TTFD!_ttfdLoadFontFile(): fs_Initialize \n");
|
|
}
|
|
|
|
// initialize info needed by NewSfnt function
|
|
|
|
pgin->sfntDirectory = (int32 *)pff->pvView; // pointer to the top of the view of the ttf file
|
|
|
|
#ifdef FE_SB
|
|
pgin->clientID = (int32)pff; // pointer to FONTFILE.
|
|
#else
|
|
pgin->clientID = (int32)pff->pvView; // pointer to the top of the
|
|
// view of the ttf file
|
|
#endif // FE_SB
|
|
|
|
pgin->GetSfntFragmentPtr = pvGetPointerCallback;
|
|
pgin->ReleaseSfntFrag = vReleasePointerCallback;
|
|
|
|
pgin->param.newsfnt.platformID = BE_UINT16(&pff->ui16PlatformID);
|
|
pgin->param.newsfnt.specificID = BE_UINT16(&pff->ui16SpecificID);
|
|
|
|
if ((iRet = fs_NewSfnt(pgin, pgout)) != NO_ERR)
|
|
{
|
|
// clean up and exit
|
|
|
|
V_FSERROR(iRet);
|
|
RET_FALSE("TTFD!_ttfdLoadFontFile(): fs_NewSfnt \n");
|
|
}
|
|
|
|
// sizes 3 and 4 returned
|
|
|
|
ASSERTDD(pff->cj3 == (ULONG)NATURAL_ALIGN(pgout->memorySizes[3]), "cj3\n");
|
|
ASSERTDD(pff->cj4 == (ULONG)NATURAL_ALIGN(pgout->memorySizes[4]), "cj4\n");
|
|
|
|
// pj3 should be shareable, but unfortunately there are fonts that
|
|
// use it to store some info there which they expect to find there at
|
|
// later times, so we have to make pj3 private as well
|
|
|
|
pgin->memoryBases[3] = pff->pj034 + (CJ_IN + CJ_OUT + CJ_0);
|
|
|
|
// not shared, private
|
|
|
|
pgin->memoryBases[4] = pgin->memoryBases[3] + pff->cj3;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Find minimal non-zero advance width
|
|
*
|
|
* Called by: ttfdOpenFontContext
|
|
*
|
|
* Routines called: bGetTablePointers
|
|
*
|
|
* History:
|
|
* 02-May-1996 [kirko]
|
|
* Added checking for table corruption.
|
|
* 22-Feb-1996 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vGetMinD(FONTFILE *pff)
|
|
{
|
|
|
|
#ifdef FE_SB
|
|
extern PBYTE pjTable(ULONG, PFONTFILE, ULONG*);
|
|
#else
|
|
extern PBYTE pjTable(ULONG, PVOID, ULONG, ULONG*);
|
|
#endif
|
|
extern BOOL bGetTablePointers(PVOID, ULONG, BYTE*, TABLE_POINTERS*);
|
|
|
|
sfnt_HorizontalHeader *phhea;
|
|
sfnt_HorizontalMetrics *phmtx;
|
|
ULONG cHMTX;
|
|
|
|
BYTE *pjView;
|
|
|
|
ULONG ig, igMin;
|
|
USHORT usMinWidth = 0xffff;
|
|
USHORT usWidth;
|
|
|
|
|
|
pjView = (BYTE *)pff->pvView;
|
|
ASSERTDD(pjView, "pjView is NULL 1\n");
|
|
ASSERTDD(pff->igMinD == USHRT_MAX, "igMinD is bogus \n");
|
|
|
|
#if DBG
|
|
{
|
|
// check for table trashing
|
|
|
|
BYTE *pj;
|
|
ULONG cj;
|
|
TABLE_ENTRY *pte;
|
|
|
|
#ifdef FE_SB
|
|
pj = pjTable('aehh', pff, &cj);
|
|
#else
|
|
pj = pjTable('aehh', pff->pvView, pff->cjView, &cj);
|
|
#endif
|
|
pte = pff->tp.ateReq + IT_REQ_HHEAD;
|
|
if ((ULONG) (pj - pjView) != pte->dp) {
|
|
RIP("FONTFILE contains bad offset to 'hhea' table\n");
|
|
} else if (cj != pte->cj) {
|
|
RIP("FONTFILE contains bad size of 'hhea' table\n");
|
|
}
|
|
|
|
#ifdef FE_SB
|
|
pj = pjTable('xtmh', pff, &cj);
|
|
#else
|
|
pj = pjTable('xtmh', pff->pvView, pff->cjView, &cj);
|
|
#endif
|
|
pte = pff->tp.ateReq + IT_REQ_HMTX;
|
|
if ((ULONG)(pj - pjView) != pte->dp) {
|
|
RIP("FONTFILE contains bad offset to 'hmtx' table\n");
|
|
} else if (cj != pte->cj) {
|
|
RIP("FONTFILE contains bad size of 'hmtx' table\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// There is a bug that causes the table of pointers to be randomly
|
|
// trashed upon entry to this routine. So, as a precaution I
|
|
// will regenerate the table at this point. This routine is called
|
|
// only upon a new realization, so the cost should not be prohibitive.
|
|
// Of course, the right thing to do is to understand and eliminate
|
|
// the source of the corruption, but this will have to do until
|
|
// that is done [kirko].
|
|
|
|
#ifndef FE_SB
|
|
if (!bGetTablePointers(pff->pvView,pff->cjView,0,&(pff->tp))) {
|
|
RIP("bGetTablePointers failed\n");
|
|
}
|
|
#endif
|
|
|
|
phhea = (sfnt_HorizontalHeader *)(pjView + pff->tp.ateReq[IT_REQ_HHEAD].dp);
|
|
phmtx = (sfnt_HorizontalMetrics *)(pjView + pff->tp.ateReq[IT_REQ_HMTX].dp);
|
|
|
|
cHMTX = (ULONG) BE_UINT16(&phhea->numberOf_LongHorMetrics);
|
|
|
|
for (ig = 0; ig < cHMTX; ig++)
|
|
{
|
|
usWidth = BE_UINT16(&phmtx[ig].advanceWidth);
|
|
if ((usWidth < usMinWidth) && (usWidth != 0))
|
|
{
|
|
usMinWidth = usWidth;
|
|
igMin = ig;
|
|
}
|
|
}
|
|
|
|
// store the results
|
|
|
|
pff->usMinD = usMinWidth;
|
|
pff->igMinD = (USHORT)igMin;
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ttfdOpenFontContext *
|
|
* *
|
|
* History: *
|
|
* 11-Nov-1991 -by- Bodin Dresevic [BodinD] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
#ifdef FE_SB
|
|
|
|
FONTCONTEXT *ttfdOpenFontContext(FONTOBJ *pfo)
|
|
{
|
|
PFONTCONTEXT pfc = PFC(NULL);
|
|
PTTC_FONTFILE pttc = (PTTC_FONTFILE)pfo->iFile;
|
|
ULONG iFace = pfo->iFace;
|
|
ULONG iFile;
|
|
PFONTFILE pff;
|
|
|
|
if (!pttc)
|
|
return((FONTCONTEXT *) NULL);
|
|
|
|
ASSERTDD(
|
|
iFace <= pttc->ulNumEntry,
|
|
"gdisrv!ttfdOpenFontContextTTC(): ulFont out of range\n"
|
|
);
|
|
|
|
iFile = PFF(pttc->ahffEntry[0].hff)->iFile;
|
|
|
|
if (pttc->cRef == 0)
|
|
{
|
|
// have to remap the file
|
|
|
|
if
|
|
(
|
|
!EngMapFontFile(
|
|
iFile,
|
|
(PULONG*)&pttc->pvView,
|
|
&pttc->cjView
|
|
)
|
|
)
|
|
{
|
|
RETURN("TTFD!_bMapTTF, somebody removed a ttf file\n",NULL);
|
|
}
|
|
}
|
|
|
|
// Get FONTFILE structure.
|
|
|
|
pff = PFF(pttc->ahffEntry[iFace-1].hff);
|
|
|
|
if (pff->cRef == 0)
|
|
{
|
|
// Update FILEVIEW structure in FONTFILE
|
|
|
|
pff->pvView = pttc->pvView;
|
|
pff->cjView = pttc->cjView;
|
|
|
|
// We have precomputed all sizes and we are allocating all memory at once:
|
|
|
|
ASSERTDD(pff->pj034 == NULL, "TTFD, pff->pj034 should be null\n");
|
|
|
|
if
|
|
(
|
|
!(pff->pj034 = (PBYTE)PV_ALLOC(
|
|
CJ_IN +
|
|
CJ_OUT +
|
|
CJ_0 +
|
|
pff->cj3 +
|
|
pff->cj4
|
|
))
|
|
)
|
|
{
|
|
if(pttc->cRef == 0)
|
|
EngUnmapFontFile(iFile);
|
|
RETURN("ttfd, MEM Alloc failed for pj034\n", NULL);
|
|
}
|
|
|
|
if (!bInitInAndOut(pff)) // could cause the exception
|
|
{
|
|
if(pttc->cRef == 0)
|
|
EngUnmapFontFile(iFile);
|
|
V_FREE(pff->pj034);
|
|
pff->pj034 = (BYTE *)NULL;
|
|
RETURN("ttfd, bInitInAndOut failed for \n", NULL);
|
|
}
|
|
|
|
// check if usMinD has been initialized, if not do it
|
|
|
|
if (!pff->usMinD)
|
|
vGetMinD(pff);
|
|
}
|
|
|
|
// allocate memory for the font context and get the pointer to font context
|
|
|
|
ASSERTDD(!pff->pfcToBeFreed, "TTFD!ttfdOpenFontContext, pfcToBeFreed NOT null\n");
|
|
|
|
if ((pff->pfcToBeFreed = pfc = pfcAlloc(sizeof(FONTCONTEXT))) ==
|
|
(FONTCONTEXT *) NULL )
|
|
{
|
|
WARNING("TTFD!_ttfdOpenFontContext, hfcAlloc failed\n");
|
|
if (pttc->cRef == 0)
|
|
EngUnmapFontFile(iFile);
|
|
if (pff->cRef == 0)
|
|
{
|
|
V_FREE(pff->pj034);
|
|
pff->pj034 = (BYTE *)NULL;
|
|
}
|
|
return((FONTCONTEXT *) NULL);
|
|
}
|
|
|
|
// state that the hff passed to this function is the FF selected in
|
|
// this font context
|
|
|
|
pfc->pfo = pfo;
|
|
pfc->pff = pff;
|
|
pfc->ptp = &pff->tp;
|
|
|
|
// parts of FONTOBJ that are important
|
|
|
|
pfc->flFontType = pfo->flFontType ;
|
|
pfc->sizLogResPpi = pfo->sizLogResPpi;
|
|
pfc->ulStyleSize = pfo->ulStyleSize ;
|
|
|
|
// tt strucs
|
|
|
|
pfc->pgin = (fs_GlyphInputType *) pfc->pff->pj034;
|
|
pfc->pgout = (fs_GlyphInfoType *) (pfc->pff->pj034 + CJ_IN);
|
|
|
|
// given the values in the context info store the transform matrix:
|
|
|
|
if (!bNewXform(pfo,pfc))
|
|
{
|
|
// clean up and exit
|
|
|
|
WARNING("TTFD!_ttfdOpenFontContext, bNewXform\n");
|
|
vFreeFC(pfc);
|
|
pff->pfcToBeFreed = NULL;
|
|
|
|
if (pttc->cRef == 0)
|
|
EngUnmapFontFile(iFile);
|
|
if (pff->cRef == 0)
|
|
{
|
|
V_FREE(pff->pj034);
|
|
pff->pj034 = (BYTE *)NULL;
|
|
}
|
|
return((FONTCONTEXT *) NULL);
|
|
}
|
|
|
|
pfc->ulControl = 0;
|
|
|
|
// 2,4,6... (n*2) is Vertical face.
|
|
|
|
pfc->bVertical = (pttc->ahffEntry[iFace-1].iFace & 0x1) ? FALSE : TRUE;
|
|
|
|
// increase the reference count of the font file, WE DO THIS ONLY WHEN
|
|
// WE ARE SURE that can not fail any more
|
|
// we have pfc, no exceptions any more
|
|
|
|
// now that we have pfc, we do not want to delete it
|
|
|
|
pff->pfcToBeFreed = NULL;
|
|
(pff->cRef)++;
|
|
(pttc->cRef)++;
|
|
return(pfc);
|
|
}
|
|
|
|
#else
|
|
|
|
FONTCONTEXT *ttfdOpenFontContext(FONTOBJ *pfo)
|
|
{
|
|
|
|
PFONTCONTEXT pfc = PFC(NULL);
|
|
PFONTFILE pff = (PFONTFILE)pfo->iFile;
|
|
|
|
ASSERTDD(pfo->iFace <= pff->ulNumFaces,
|
|
"gdisrv!ttfdOpenFontContext(): ulFont out of range\n");
|
|
|
|
if (!pff)
|
|
return((FONTCONTEXT *) NULL);
|
|
|
|
if (pff->cRef == 0)
|
|
{
|
|
// have to remap the file
|
|
|
|
if
|
|
(
|
|
!EngMapFontFile(
|
|
pff->iFile,
|
|
(PULONG*)&pff->pvView,
|
|
&pff->cjView
|
|
)
|
|
)
|
|
{
|
|
RETURN("TTFD!ttfdOpenFontContext: bMapFileUNICODE failed\n",NULL);
|
|
}
|
|
|
|
ASSERTDD(pff->pj034 == NULL, "pff->pj034 should be null\n");
|
|
|
|
// We have precomputed all sizes and we are allocating all memory at once:
|
|
|
|
if
|
|
(
|
|
!(pff->pj034 = (PBYTE)PV_ALLOC(
|
|
CJ_IN +
|
|
CJ_OUT +
|
|
CJ_0 +
|
|
pff->cj3 +
|
|
pff->cj4
|
|
))
|
|
)
|
|
{
|
|
EngUnmapFontFile(pff->iFile);
|
|
RETURN("ttfd, MEM Alloc failed for pj034\n", NULL);
|
|
}
|
|
|
|
if (!bInitInAndOut(pff)) // could cause the exception
|
|
{
|
|
EngUnmapFontFile(pff->iFile);
|
|
V_FREE(pff->pj034);
|
|
pff->pj034 = (BYTE *)NULL;
|
|
RETURN("ttfd, bInitInAndOut failed for \n", NULL);
|
|
}
|
|
|
|
// check if usMinD has been initialized, if not do it
|
|
|
|
if (!pff->usMinD)
|
|
vGetMinD(pff);
|
|
}
|
|
|
|
// allocate memory for the font context and get the pointer to font context
|
|
|
|
ASSERTDD(!pff->pfcToBeFreed, "ttfdOpenFontContext, pfcToBeFreed NOT null\n");
|
|
|
|
if ((pff->pfcToBeFreed = pfc = pfcAlloc(sizeof(FONTCONTEXT))) == (FONTCONTEXT *) NULL )
|
|
{
|
|
WARNING("TTFD!_ttfdOpenFontContext, hfcAlloc failed\n");
|
|
if (pff->cRef == 0)
|
|
{
|
|
EngUnmapFontFile(pff->iFile);
|
|
V_FREE(pff->pj034);
|
|
pff->pj034 = (BYTE *)NULL;
|
|
}
|
|
return((FONTCONTEXT *) NULL);
|
|
}
|
|
|
|
// state that the hff passed to this function is the FF selected in
|
|
// this font context
|
|
|
|
pfc->pfo = pfo;
|
|
pfc->pff = pff;
|
|
pfc->ptp = &pff->tp;
|
|
|
|
// parts of FONTOBJ that are important
|
|
|
|
pfc->flFontType = pfo->flFontType ;
|
|
pfc->sizLogResPpi = pfo->sizLogResPpi;
|
|
pfc->ulStyleSize = pfo->ulStyleSize ;
|
|
|
|
// tt strucs
|
|
|
|
pfc->pgin = (fs_GlyphInputType *) pfc->pff->pj034;
|
|
pfc->pgout = (fs_GlyphInfoType *) (pfc->pff->pj034 + CJ_IN);
|
|
|
|
// given the values in the context info store the transform matrix:
|
|
|
|
if (!bNewXform(pfo,pfc))
|
|
{
|
|
// clean up and exit
|
|
|
|
WARNING("TTFD!_ttfdOpenFontContext, bNewXform\n");
|
|
vFreeFC(pfc);
|
|
pff->pfcToBeFreed = NULL;
|
|
|
|
if (pff->cRef == 0)
|
|
{
|
|
EngUnmapFontFile(pff->iFile);
|
|
V_FREE(pff->pj034);
|
|
pff->pj034 = (BYTE *)NULL;
|
|
}
|
|
return((FONTCONTEXT *) NULL);
|
|
}
|
|
|
|
pfc->ulControl = 0;
|
|
pfc->bVertical = ((pfo->iFace == 2) ? TRUE : FALSE);
|
|
|
|
// increase the reference count of the font file, WE DO THIS ONLY WHEN
|
|
// WE ARE SURE that can not fail any more
|
|
// we have pfc, no exceptions any more
|
|
|
|
// now that we have pfc, we do not want to delete it
|
|
|
|
pff->pfcToBeFreed = NULL;
|
|
(pff->cRef)++;
|
|
return(pfc);
|
|
}
|
|
#endif
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ttfdCloseFontContext
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
*
|
|
* History:
|
|
* 11-Nov-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
#ifdef FE_SB
|
|
BOOL
|
|
ttfdCloseFontContext (
|
|
FONTCONTEXT *pfc
|
|
)
|
|
{
|
|
PTTC_FONTFILE pttc;
|
|
PFONTFILE pff;
|
|
|
|
if (pfc == (FONTCONTEXT *) NULL)
|
|
return(FALSE);
|
|
|
|
pff = pfc->pff;
|
|
pttc = pfc->pff->pttc;
|
|
|
|
// decrement the reference count for the corresponding FONTFILE
|
|
|
|
ASSERTDD(pff->cRef > 0L, "TTFD!_CloseFontContext: cRef <= 0 \n");
|
|
|
|
pff->cRef--;
|
|
pttc->cRef--;
|
|
|
|
// if this was the last fc that last used the buffer at pj3, invalidate
|
|
// the associated pfcLast
|
|
|
|
if (pff->pfcLast == pfc)
|
|
pff->pfcLast = PFC(NULL);
|
|
|
|
// in case that this is happening after the exception, make sure to release
|
|
// any memory that may have possibly been allocated to perform queries
|
|
// on per character basis:
|
|
|
|
if (pttc->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
{
|
|
// if exception this memory has already been freed
|
|
|
|
ASSERTDD(!pff->pj034, "\n TTFD! pff->pj3 is NOT null\n");
|
|
|
|
if (pfc->gstat.pv) // this may or may have not been allocated
|
|
{
|
|
V_FREE(pfc->gstat.pv);
|
|
pfc->gstat.pv = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERTDD(pff->pj034, "\n TTFD! pff->pj3 is null\n");
|
|
}
|
|
|
|
if (pff->cRef == 0)
|
|
{
|
|
// there are no fc's around to use memory at pff->pj3, release it.
|
|
|
|
if (!(pttc->fl & FF_EXCEPTION_IN_PAGE_ERROR))
|
|
{
|
|
V_FREE(pff->pj034);
|
|
pff->pj034 = (BYTE *)NULL;
|
|
}
|
|
}
|
|
|
|
if (pttc->cRef == 0)
|
|
{
|
|
// file will not be used for a while,
|
|
|
|
EngUnmapFontFile(PFF(pttc->ahffEntry[0].hff)->iFile);
|
|
}
|
|
|
|
// free the memory associated with hfc
|
|
|
|
vFreeFC(pfc);
|
|
return(TRUE);
|
|
}
|
|
#else
|
|
BOOL
|
|
ttfdCloseFontContext (
|
|
FONTCONTEXT *pfc
|
|
)
|
|
{
|
|
PFONTFILE pff;
|
|
|
|
if (pfc == (FONTCONTEXT *) NULL)
|
|
return(FALSE);
|
|
|
|
pff = pfc->pff;
|
|
|
|
// decrement the reference count for the corresponding FONTFILE
|
|
|
|
ASSERTDD(pff->cRef > 0L, "CloseFontContext: cRef <= 0 \n");
|
|
|
|
pff->cRef--;
|
|
|
|
// if this was the last fc that last used the buffer at pj3, invalidate
|
|
// the associated pfcLast
|
|
|
|
if (pff->pfcLast == pfc)
|
|
pff->pfcLast = PFC(NULL);
|
|
|
|
// in case that this is happening after the exception, make sure to release
|
|
// any memory that may have possibly been allocated to perform queries
|
|
// on per character basis:
|
|
|
|
if (pff->fl & FF_EXCEPTION_IN_PAGE_ERROR)
|
|
{
|
|
// if exception this memory has already been freed
|
|
|
|
ASSERTDD(!pff->pj034, "\n pff->pj3 is NOT null\n");
|
|
|
|
if (pfc->gstat.pv) // this may or may have not been allocated
|
|
{
|
|
V_FREE(pfc->gstat.pv);
|
|
pfc->gstat.pv = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERTDD(pff->pj034, "\n pff->pj3 is null\n");
|
|
}
|
|
|
|
if (pff->cRef == 0)
|
|
{
|
|
// there are no fc's around to use memory at pff->pj3, release it.
|
|
|
|
if (!(pff->fl & FF_EXCEPTION_IN_PAGE_ERROR))
|
|
{
|
|
V_FREE(pff->pj034);
|
|
pff->pj034 = (BYTE *)NULL;
|
|
}
|
|
|
|
// file will not be used for a while,
|
|
|
|
EngUnmapFontFile(pff->iFile);
|
|
}
|
|
|
|
// free the memory associated with hfc
|
|
|
|
vFreeFC(pfc);
|
|
return(TRUE);
|
|
}
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ttfdDestroyFont
|
|
*
|
|
* Driver can release all resources associated with this font realization
|
|
* (embodied in the FONTOBJ).
|
|
*
|
|
* History:
|
|
* 27-Oct-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
ttfdDestroyFont (
|
|
FONTOBJ *pfo
|
|
)
|
|
{
|
|
// For the ttfd, this is simply closing the font context.
|
|
// We cleverly store the font context handle in the FONTOBJ pvProducer
|
|
// field.
|
|
|
|
// pfo->pvProducer COULD BE null if exception occured while trying to create fc
|
|
|
|
if (pfo->pvProducer)
|
|
{
|
|
ttfdCloseFontContext((FONTCONTEXT *) pfo->pvProducer);
|
|
pfo->pvProducer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ttfdFree
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* History:
|
|
* 27-Oct-1992 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
ttfdFree (
|
|
PVOID pv,
|
|
ULONG id
|
|
)
|
|
{
|
|
DYNAMICDATA *pdd;
|
|
|
|
//
|
|
// If id is NULL, then we can ignore.
|
|
//
|
|
if ( (pdd = (DYNAMICDATA *) id) == (DYNAMICDATA *) NULL )
|
|
return;
|
|
|
|
// What kind of data?
|
|
//
|
|
switch (pdd->ulDataType)
|
|
{
|
|
case ID_KERNPAIR:
|
|
|
|
// Invalidate the cached pointer to the data.
|
|
|
|
pdd->pff->pkp = NULL; // important to check at vUnloadFontFile time
|
|
|
|
// Free the kerning pair buffer and DYNAMICDATA structure.
|
|
|
|
pv; // we ignore pv because it is part of the mem allocated with DYNAMICDATA structure.
|
|
V_FREE(pdd); // this frees both the DYNAMICDATA struct and the FD_KERNINGPAIR buffer.
|
|
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Don't do anything.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bSetXform
|
|
*
|
|
* the only reason this funcion can fail is if fs_NewTransformation has failed
|
|
* Needs to be called when the transform has changed relative to the
|
|
* transform stored in this fc
|
|
*
|
|
* History:
|
|
* 28-Mar-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL bSetXform (
|
|
PFONTCONTEXT pfc
|
|
)
|
|
{
|
|
FS_ENTRY iRet;
|
|
transMatrix mx = pfc->mx;
|
|
Fixed fxScale;
|
|
LONG ptSize;
|
|
|
|
// no previous glyph metric computation can be used
|
|
|
|
vInitGlyphState(&pfc->gstat);
|
|
|
|
// if an illegal junk is passed for style size replace by reasonable default
|
|
|
|
if (pfc->ulStyleSize > SHRT_MAX)
|
|
pfc->ulStyleSize = 0;
|
|
|
|
pfc->pgin->param.newtrans.xResolution = (int16)pfc->sizLogResPpi.cx;
|
|
pfc->pgin->param.newtrans.yResolution = (int16)pfc->sizLogResPpi.cy;
|
|
|
|
if (pfc->flXform & XFORM_SINGULAR)
|
|
{
|
|
// just put in some junk so that the preprogram does not explode
|
|
|
|
pfc->pgin->param.newtrans.pointSize = LTOF16_16(12);
|
|
|
|
mx.transform[0][0] = LTOF16_16(1);
|
|
mx.transform[1][0] = 0;
|
|
mx.transform[1][1] = LTOF16_16(1);
|
|
mx.transform[0][1] = 0;
|
|
}
|
|
else
|
|
{
|
|
if (pfc->flXform & XFORM_HORIZ)
|
|
{
|
|
if (pfc->ulStyleSize == 0)
|
|
{
|
|
// hinting is determined by ptSize that corresponds to the
|
|
// actual height in points of the font
|
|
|
|
pfc->pgin->param.newtrans.pointSize = pfc->fxPtSize;
|
|
|
|
// factor out pointSize from the xform:
|
|
|
|
if (pfc->mx.transform[1][1] > 0)
|
|
mx.transform[1][1] = LTOF16_16(1);
|
|
else
|
|
mx.transform[1][1] = LTOF16_16(-1);
|
|
|
|
if
|
|
(
|
|
(pfc->mx.transform[1][1] == pfc->mx.transform[0][0])
|
|
&&
|
|
(pfc->sizLogResPpi.cy == pfc->sizLogResPpi.cx)
|
|
)
|
|
{
|
|
// important special case, simplify computation
|
|
|
|
mx.transform[0][0] = mx.transform[1][1];
|
|
}
|
|
else // general case
|
|
{
|
|
fxScale = LongMulDiv(
|
|
LTOF16_16(pfc->pff->ui16EmHt),pfc->sizLogResPpi.cy,
|
|
pfc->lEmHtDev * pfc->sizLogResPpi.cx
|
|
);
|
|
|
|
mx.transform[0][0] = FixMul(mx.transform[0][0], fxScale);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This is the support for new optical scaling feature.
|
|
// Hint the font as determined by the style point size from
|
|
// ExtLogFont, but possibly zoom the font to a different
|
|
// physical size
|
|
|
|
pfc->pgin->param.newtrans.pointSize =
|
|
(Fixed)LTOF16_16(pfc->ulStyleSize);
|
|
|
|
// factor out pointSize from the xform:
|
|
|
|
fxScale = LongMulDiv(LTOF16_16(pfc->pff->ui16EmHt),72,
|
|
pfc->ulStyleSize * pfc->sizLogResPpi.cx
|
|
);
|
|
|
|
mx.transform[0][0] = FixMul(mx.transform[0][0], fxScale);
|
|
|
|
if (pfc->sizLogResPpi.cy != pfc->sizLogResPpi.cx)
|
|
{
|
|
fxScale = LongMulDiv(LTOF16_16(pfc->pff->ui16EmHt),72,
|
|
pfc->ulStyleSize * pfc->sizLogResPpi.cy
|
|
);
|
|
}
|
|
|
|
mx.transform[1][1] = FixMul(mx.transform[1][1], fxScale);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pfc->ulStyleSize == 0)
|
|
{
|
|
// compute the physical point size
|
|
|
|
ptSize = F16_16TOLROUND(pfc->fxPtSize);
|
|
pfc->pgin->param.newtrans.pointSize = pfc->fxPtSize;
|
|
}
|
|
else // use style size from logfont, the support for optical scaling
|
|
{
|
|
ptSize = pfc->ulStyleSize;
|
|
pfc->pgin->param.newtrans.pointSize = LTOF16_16(pfc->ulStyleSize);
|
|
}
|
|
|
|
// factor out pointSize from the xform:
|
|
|
|
fxScale = LongMulDiv(LTOF16_16(pfc->pff->ui16EmHt),72,
|
|
ptSize * pfc->sizLogResPpi.cx
|
|
);
|
|
|
|
mx.transform[0][0] = FixMul(mx.transform[0][0], fxScale);
|
|
mx.transform[1][0] = FixMul(mx.transform[1][0], fxScale);
|
|
|
|
if (pfc->sizLogResPpi.cy != pfc->sizLogResPpi.cx)
|
|
{
|
|
fxScale = LongMulDiv(LTOF16_16(pfc->pff->ui16EmHt),72,
|
|
ptSize * pfc->sizLogResPpi.cy
|
|
);
|
|
}
|
|
|
|
mx.transform[1][1] = FixMul(mx.transform[1][1], fxScale);
|
|
mx.transform[0][1] = FixMul(mx.transform[0][1], fxScale);
|
|
}
|
|
|
|
}
|
|
|
|
// last minute modification to the matrix if italicization is present:
|
|
|
|
if (pfc->flFontType & FO_SIM_ITALIC)
|
|
{
|
|
// the result of multiplying arbitrary matrix with italicization matrix
|
|
// We are multiplying from the left because the italicization matrix
|
|
// acts first on the notional space vectors on the left
|
|
//
|
|
// |1 0| |m00 m01| |m00 m10 |
|
|
// | | * | | = | |
|
|
// |sin20 1| |m10 m11| |m10 + m00 * sin20 m11 + m01 * sin20|
|
|
//
|
|
|
|
mx.transform[1][0] += FixMul(mx.transform[0][0], FX_SIN20);
|
|
mx.transform[1][1] += FixMul(mx.transform[0][1], FX_SIN20);
|
|
}
|
|
|
|
pfc->pgin->param.newtrans.transformMatrix = &mx;
|
|
|
|
// FIXEDSQRT2 is good as pixel diameter for all practical purposes
|
|
// according to EliK, LenoxB and JeanP [bodind]
|
|
|
|
if ( pfc->bVertical )
|
|
{
|
|
//
|
|
// keep these values for later
|
|
//
|
|
pfc->mxn = mx;
|
|
pfc->pointSize = pfc->pgin->param.newtrans.pointSize;
|
|
//
|
|
// call the transformation matrix calculation function
|
|
// for vertical glyphs just before calling fs_NewTransformation.
|
|
//
|
|
vCalcXformVertical( pfc );
|
|
}
|
|
|
|
pfc->pgin->param.newtrans.pixelDiameter = FIXEDSQRT2;
|
|
pfc->pgin->param.newtrans.traceFunc = (FntTraceFunc)NULL;
|
|
|
|
// now call the rasterizer to acknowledge the new transform
|
|
|
|
if ((iRet = fs_NewTransformation(pfc->pgin, pfc->pgout)) != NO_ERR)
|
|
{
|
|
V_FSERROR(iRet);
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID vQuantizeXform
|
|
(
|
|
PFONTCONTEXT pfc
|
|
);
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* STATIC bComputeMaxGlyph
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* History:
|
|
* 04-Dec-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
STATIC BOOL
|
|
bComputeMaxGlyph (
|
|
PFONTCONTEXT pfc
|
|
)
|
|
{
|
|
VOID vSetGrayState__FONTCONTEXT(FONTCONTEXT *);
|
|
LONG cxMax,cyMax;
|
|
|
|
LONG yMinN, yMaxN;
|
|
LONG xMinN, xMaxN;
|
|
|
|
LONG lTmp;
|
|
Fixed fxMxx,fxMyy;
|
|
BYTE *pjView = (BYTE *)pfc->pff->pvView;
|
|
|
|
sfnt_FontHeader * phead = (sfnt_FontHeader *) (
|
|
pjView + pfc->ptp->ateReq[IT_REQ_HEAD].dp
|
|
);
|
|
|
|
BYTE * pjOS2 = (pfc->ptp->ateOpt[IT_OPT_OS2].dp) ?
|
|
(pjView + pfc->ptp->ateOpt[IT_OPT_OS2].dp) :
|
|
NULL ;
|
|
|
|
ASSERTDD(pjView, "bComputeMaxGlyph, pjView\n");
|
|
|
|
// get the notional space values
|
|
|
|
if (pjOS2 && (pfc->flXform & (XFORM_HORIZ | XFORM_VERT)))
|
|
{
|
|
// win 31 compatibility: we only take the max over win 31 char set:
|
|
// all the glyphs outside this set, if they stand out will get chopped
|
|
// off to match the height of the win31 char subset:
|
|
|
|
yMinN = - BE_INT16(pjOS2 + OFF_OS2_usWinAscent);
|
|
yMaxN = BE_INT16(pjOS2 + OFF_OS2_usWinDescent);
|
|
}
|
|
else
|
|
{
|
|
yMinN = - BE_INT16(&phead->yMax);
|
|
yMaxN = - BE_INT16(&phead->yMin);
|
|
}
|
|
|
|
ASSERTDD(yMinN < yMaxN, "yMinN >= yMaxN\n");
|
|
|
|
xMinN = BE_INT16(&phead->xMin);
|
|
xMaxN = BE_INT16(&phead->xMax);
|
|
|
|
if (pfc->flFontType & FO_SIM_ITALIC)
|
|
{
|
|
// IF there is italic simulation
|
|
// xMin -> xMin - yMaxN * sin20
|
|
// xMax -> yMax - yMinN * sin20
|
|
|
|
xMinN -= FixMul(yMaxN, FX_SIN20);
|
|
xMaxN -= FixMul(yMinN, FX_SIN20);
|
|
}
|
|
|
|
ASSERTDD(xMinN < xMaxN, "xMinN >= xMaxN\n");
|
|
|
|
pfc->lEmHtDev = 0; // flag that it has not been computed
|
|
pfc->fxPtSize = 0; // flag that it has not been computed
|
|
pfc->lD = 0; // zero unless computed otherwise
|
|
pfc->phdmx = NULL; // NULL unless computed otherwise
|
|
|
|
if (pfc->flXform & XFORM_HORIZ) // XX AND YY Only
|
|
{
|
|
sfnt_HorizontalHeader *phhea;
|
|
ULONG cHMTX;
|
|
|
|
fxMxx = pfc->mx.transform[0][0];
|
|
fxMyy = pfc->mx.transform[1][1];
|
|
|
|
// ascender, round up
|
|
|
|
yMinN = FixMul(fxMyy, yMinN);
|
|
yMaxN = FixMul(fxMyy, yMaxN);
|
|
|
|
if (fxMyy > 0)
|
|
{
|
|
// vdmx table should be consulted if present and used to compute
|
|
// ascender and descender. If this computation can not be done
|
|
// based on vdmx table or if vdmx table is not present simple
|
|
// linear scaling will suffice [bodind].
|
|
|
|
vQuantizeXform(pfc);
|
|
|
|
if (!(pfc->flXform & XFORM_VDMXEXTENTS)) // COMPUTED FROM VDMX
|
|
{
|
|
pfc->yMin = yMinN;
|
|
pfc->yMax = yMaxN;
|
|
}
|
|
|
|
pfc->lAscDev = - pfc->yMin;
|
|
pfc->lDescDev = pfc->yMax;
|
|
}
|
|
else // fxMyy < 0
|
|
{
|
|
pfc->lAscDev = yMinN;
|
|
pfc->lDescDev = - yMaxN;
|
|
|
|
// swap yMin and yMax for when the xform flips y coord
|
|
|
|
lTmp = yMinN;
|
|
yMinN = yMaxN;
|
|
yMaxN = lTmp;
|
|
|
|
pfc->yMin = yMinN;
|
|
pfc->yMax = yMaxN;
|
|
|
|
}
|
|
|
|
if (pfc->lEmHtDev == 0)
|
|
{
|
|
// if this value has not been computed in vQuantizeXform routine
|
|
|
|
pfc->lEmHtDev = FixMul(fxMyy, pfc->pff->ifi.fwdUnitsPerEm);
|
|
if (pfc->lEmHtDev < 0)
|
|
pfc->lEmHtDev = - pfc->lEmHtDev;
|
|
}
|
|
|
|
ASSERTDD(pfc->lEmHtDev >= 0, "lEmHt negative\n");
|
|
|
|
// now that em height has been computed, we can compute the
|
|
// pt size on the rendering device. This value will be fed to
|
|
// fs_NewTransformation
|
|
|
|
pfc->fxPtSize = LongMulDiv(
|
|
LTOF16_16(pfc->lEmHtDev), 72,
|
|
pfc->sizLogResPpi.cy);
|
|
|
|
cyMax = pfc->yMax - pfc->yMin;
|
|
|
|
if
|
|
(
|
|
(pfc->flXform & XFORM_HORIZ) &&
|
|
(pfc->mx.transform[0][0] == pfc->mx.transform[1][1]) &&
|
|
(pfc->mx.transform[1][1] > 0)
|
|
)
|
|
{
|
|
// caution, do not move this line of code elsewhere for
|
|
// this check has to be made after vQuantizeXform since
|
|
// this function may change the transform, but it has to be
|
|
// made before bGetFastAdvanceWidth or bQueryAdvanceWidths
|
|
// are ever called for these functions check flXform agains
|
|
// XFORM_POSITIVE_SCALE
|
|
|
|
pfc->flXform |= XFORM_POSITIVE_SCALE;
|
|
|
|
// find the hdmx table, in case of the console fixed pitch font this
|
|
// table may be useful in determining if cxMax needs to be cut off
|
|
// to the advance width of this font
|
|
|
|
vFindHdmxTable(pfc); // this could cause an exception:
|
|
}
|
|
|
|
phhea = (sfnt_HorizontalHeader *)(
|
|
(BYTE *)pfc->pff->pvView + pfc->ptp->ateReq[IT_REQ_HHEAD].dp
|
|
);
|
|
cHMTX = (ULONG) BE_UINT16(&phhea->numberOf_LongHorMetrics);
|
|
|
|
// ig == cHMTX - 1; pick the last width from hmtx table.
|
|
// If we use ig == 0 as I originally intended, turns out this
|
|
// field is usually hacked and set to zero. ig == 0 corresponds to
|
|
// apple logo which is not allowed in msft fonts.
|
|
// We should only do this with new console fonts, not with the old style
|
|
// fixed pitch fonts that may have negative a and c spaces
|
|
|
|
if(
|
|
(!IS_ANY_DBCS_CHARSET(pfc->pff->ifi.jWinCharSet)) &&
|
|
(pfc->pff->ifi.flInfo & FM_INFO_OPTICALLY_FIXED_PITCH) &&
|
|
(pfc->flXform & XFORM_POSITIVE_SCALE) &&
|
|
!(pfc->flFontType & FO_SIM_ITALIC) &&
|
|
(pfc->pff->ifi.flInfo & FM_INFO_NONNEGATIVE_AC) &&
|
|
bGetFastAdvanceWidth(pfc,cHMTX - 1, &pfc->lD)
|
|
)
|
|
{
|
|
pfc->lD = FXTOLROUND(pfc->lD);
|
|
|
|
// do this before possibly adding 1 for emboldening, for
|
|
// these quantities refer to what rasterizer will return
|
|
|
|
pfc->xMin = 0;
|
|
pfc->xMax = pfc->lD;
|
|
|
|
// we want emboldened fonts in console:
|
|
|
|
if (pfc->flFontType & FO_SIM_BOLD)
|
|
pfc->lD += 1;
|
|
|
|
// for the console fonts we want to be sure that every glyph fits in
|
|
// in the box of the width lD and height equal to asc+desc.
|
|
|
|
pfc->cxMax = cxMax = (ULONG)pfc->lD;
|
|
}
|
|
else
|
|
{
|
|
// even though this may be a fixed pitch font we shall not optimize in this
|
|
// case, for this is not a frequently used type of transform.
|
|
|
|
pfc->lD = 0;
|
|
|
|
// scale xMin,xMax to device, 28.4 format
|
|
|
|
xMinN = FixMul(LTOFX(xMinN), fxMxx);
|
|
xMaxN = FixMul(LTOFX(xMaxN), fxMxx);
|
|
|
|
if (fxMxx < 0)
|
|
{
|
|
lTmp = xMinN;
|
|
xMinN = xMaxN;
|
|
xMaxN = lTmp;
|
|
}
|
|
|
|
// I run the experiment on 400 fonts at several sizes. I found
|
|
// that subtracting 2 from xMin and adding 1 to xMax suffices
|
|
// in all situations to prevent any columns from being shaved off.
|
|
// [bodind]
|
|
|
|
xMinN = FXTOLFLOOR(xMinN) - 2;
|
|
xMaxN = FXTOLCEILING(xMaxN) + 1;
|
|
|
|
pfc->xMin = xMinN;
|
|
pfc->xMax = xMaxN;
|
|
|
|
cxMax = xMaxN - xMinN;
|
|
}
|
|
|
|
// the direction unit vectors for scaling transforms are simple
|
|
// if the font is intended for horizontal left to right writing
|
|
|
|
//!!! here the check is due to verify that the font is not designed
|
|
//!!! for vertical writing in the notional space [bodind]
|
|
|
|
vLToE(&pfc->pteUnitBase.x, (fxMxx > 0) ? 1L : - 1L);
|
|
vLToE(&pfc->pteUnitBase.y, 0L);
|
|
vLToE(&pfc->pteUnitSide.x, 0L);
|
|
vLToE(&pfc->pteUnitSide.y, (fxMyy > 0) ? -1L : 1L); // y axis points down
|
|
|
|
// We need to adjust the the glyph origin of singular bitmaps for glyphs
|
|
// when MaxAscent or MaxDescent is negative or zero. The trick is to choose
|
|
// these values so that the "blank" glyph is always included in the
|
|
// rectangle of the text. What this means is that
|
|
// for m11 > 0 we must have: yT >= -lAsc && yB <= lDesc
|
|
// for m11 < 0 we must have: yT >= -lDesc && yB <= lAsc
|
|
// here yB == yT + 1, because blank glyphs has a cy == 1, and
|
|
// yT == ptlSingularOrigin.y
|
|
// This leads to
|
|
// for m11 > 0 we must have: - (lAsc + 1) < yT < lDesc
|
|
// for m11 < 0 we must have: - (lDesc + 1) < yT < lAsc
|
|
// One point that would satisfy both of these conditions is
|
|
// the midpoint between the endpoints. Thus, before any rouding:
|
|
// for m11 > 0 we have: yT = (lDesc- lAsc - 1)/2
|
|
// for m11 < 0 we have: yT = -(lDesc- lAsc - 1)/2
|
|
// where divide by 2 is not integer divide but ordinary real number divide.
|
|
// The proper rounding is done ala KirkO, that is, add 1/2 and take a
|
|
// flor:
|
|
// for m11 > 0 we have: yT = FLOOR((lDesc - lAsc - 1)/2 + 1/2)
|
|
// for m11 < 0 we have: yT = FLOOR((lAsc - lDesc - 1)/2 + 1/2)
|
|
// That is:
|
|
// for m11 > 0 we have: yT = FLOOR(lDesc - lAsc)/2)
|
|
// for m11 < 0 we have: yT = FLOOR(lAsc - lDesc)/2)
|
|
// Now floor is computed correctly (on signed nubmers) by implementing
|
|
// divide by 2 as >> 1 operation:
|
|
|
|
pfc->ptlSingularOrigin.x = 0;
|
|
|
|
if ((pfc->lAscDev <= 0) || (pfc->lDescDev <= 0))
|
|
{
|
|
if (pfc->mx.transform[1][1] > 0)
|
|
{
|
|
pfc->ptlSingularOrigin.y =
|
|
(pfc->lDescDev - pfc->lAscDev) >> 1;
|
|
}
|
|
else
|
|
{
|
|
pfc->ptlSingularOrigin.y =
|
|
(pfc->lAscDev - pfc->lDescDev) >> 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pfc->ptlSingularOrigin.y = 0;
|
|
}
|
|
|
|
}
|
|
else // nontrivial transformation
|
|
{
|
|
POINTL aptl[4];
|
|
POINTFIX aptfx[4];
|
|
BOOL bOk;
|
|
INT i;
|
|
FIX xMinD, xMaxD, yMinD, yMaxD; // device space values;
|
|
|
|
// add little extra space to be safe
|
|
|
|
i = (INT)(pfc->pff->ui16EmHt / 64);
|
|
yMaxN += i; // adds about 1.7% to ht
|
|
yMinN -= i; // adds about 1.7% to ht
|
|
|
|
// set up the input array, the four corners of the maximal bounding
|
|
// box in the notional coords
|
|
|
|
aptl[0].x = xMinN; // tl.x
|
|
aptl[0].y = yMinN; // tl.y
|
|
|
|
aptl[1].x = xMaxN; // tr.x
|
|
aptl[1].y = yMinN; // tr.y
|
|
|
|
aptl[2].x = xMinN; // bl.x
|
|
aptl[2].y = yMaxN; // bl.y
|
|
|
|
aptl[3].x = xMaxN; // br.x
|
|
aptl[3].y = yMaxN; // br.y
|
|
|
|
// xform to device coords with 28.4 precision:
|
|
|
|
// !!! [GilmanW] 27-Oct-1992
|
|
// !!! Should change over to engine user object helper functions
|
|
// !!! instead of the fontmath.cxx functions.
|
|
|
|
bOk = bFDXform(&pfc->xfm, aptfx, aptl, 4);
|
|
|
|
if (!bOk) { RETURN("TTFD!_:bFDXform\n", FALSE); }
|
|
|
|
xMaxD = xMinD = aptfx[0].x;
|
|
yMaxD = yMinD = aptfx[0].y;
|
|
|
|
for (i = 1; i < 4; i++)
|
|
{
|
|
if (aptfx[i].x < xMinD)
|
|
xMinD = aptfx[i].x;
|
|
if (aptfx[i].x > xMaxD)
|
|
xMaxD = aptfx[i].x;
|
|
if (aptfx[i].y < yMinD)
|
|
yMinD = aptfx[i].y;
|
|
if (aptfx[i].y > yMaxD)
|
|
yMaxD = aptfx[i].y;
|
|
}
|
|
|
|
yMinD = FXTOLFLOOR(yMinD) ;
|
|
yMaxD = FXTOLCEILING(yMaxD) ;
|
|
xMinD = FXTOLFLOOR(xMinD) ;
|
|
xMaxD = FXTOLCEILING(xMaxD) ;
|
|
|
|
cxMax = xMaxD - xMinD;
|
|
cyMax = yMaxD - yMinD;
|
|
|
|
// now re-use aptl to store e1 and -e2, base and side unit
|
|
// vectors in the notional space.
|
|
//!!! This may be wrong if have font for
|
|
//!!! right to left or vert writing [bodind]
|
|
|
|
aptl[0].x = 1; // base.x
|
|
aptl[0].y = 0; // base.y
|
|
|
|
aptl[1].x = 0; // side.x
|
|
aptl[1].y = -1; // side.y
|
|
|
|
// !!! [GilmanW] 27-Oct-1992
|
|
// !!! Should change over to engine user object helper functions
|
|
// !!! instead of the fontmath.cxx functions.
|
|
|
|
bOk = bXformUnitVector (
|
|
&aptl[0], // IN, incoming unit vector
|
|
&pfc->xfm, // IN, xform to use
|
|
&pfc->vtflBase, // OUT, xform of the incoming unit vector
|
|
&pfc->pteUnitBase, // OUT, *pptqXormed/|*pptqXormed|, POINTE
|
|
(pfc->flFontType & FO_SIM_BOLD) ? &pfc->ptqUnitBase : NULL, // OUT, *pptqXormed/|*pptqXormed|, POINTQF
|
|
&pfc->efBase // OUT, |*pptqXormed|
|
|
);
|
|
|
|
bOk &= bXformUnitVector (
|
|
&aptl[1], // IN, incoming unit vector
|
|
&pfc->xfm, // IN, xform to use
|
|
&pfc->vtflSide, // OUT, xform of the incoming unit vector
|
|
&pfc->pteUnitSide, // OUT, *pptqXormed/|*pptqXormed|, POINTE
|
|
NULL,
|
|
&pfc->efSide // OUT, |*pptqXormed|
|
|
);
|
|
|
|
if (!bOk) { RETURN("TTFD!_:bXformUnitVector\n", FALSE); }
|
|
|
|
pfc->lAscDev = -fxLTimesEf(&pfc->efSide,yMinN);
|
|
pfc->lDescDev = fxLTimesEf(&pfc->efSide,yMaxN);
|
|
|
|
pfc->lAscDev = FXTOLCEILING(pfc->lAscDev) ;
|
|
pfc->lDescDev = FXTOLCEILING(pfc->lDescDev);
|
|
|
|
pfc->ptfxTop.x = lExL(pfc->pteUnitSide.x, LTOFX(pfc->lAscDev));
|
|
pfc->ptfxTop.y = lExL(pfc->pteUnitSide.y, LTOFX(pfc->lAscDev));
|
|
pfc->ptfxBottom.x = lExL(pfc->pteUnitSide.x, -LTOFX(pfc->lDescDev));
|
|
pfc->ptfxBottom.y = lExL(pfc->pteUnitSide.y, -LTOFX(pfc->lDescDev));
|
|
|
|
if ((yMinN >= 0) || (yMaxN <= 0) || ((pfc->lAscDev + pfc->lDescDev) < 3))
|
|
{
|
|
// Either all the glyphs are above the base line or all the glyphs
|
|
// are below the baseline. In either case adjust the origin for
|
|
// the singular glyph bitmap.
|
|
// Compute the midpoint between asc and desc in notional space:
|
|
// lAverage = ROUND(-(yMaxN+yMinN)/2)
|
|
|
|
LONG lAverage = (-yMaxN -yMinN + 1) >> 1;
|
|
|
|
pfc->ptlSingularOrigin.x = fxLTimesEf(&pfc->vtflSide.x,lAverage);
|
|
pfc->ptlSingularOrigin.x = FXTOLROUND(pfc->ptlSingularOrigin.x);
|
|
|
|
pfc->ptlSingularOrigin.y = fxLTimesEf(&pfc->vtflSide.y,lAverage);
|
|
pfc->ptlSingularOrigin.y = FXTOLROUND(pfc->ptlSingularOrigin.y);
|
|
|
|
}
|
|
else
|
|
{
|
|
pfc->ptlSingularOrigin.x = 0;
|
|
pfc->ptlSingularOrigin.y = 0;
|
|
}
|
|
|
|
|
|
// finally store the results:
|
|
|
|
pfc->xMin = xMinD;
|
|
pfc->xMax = xMaxD;
|
|
pfc->yMin = yMinD;
|
|
pfc->yMax = yMaxD;
|
|
|
|
// compute em ht in pixels and points
|
|
|
|
pfc->lEmHtDev = FixMul(
|
|
iHipot(pfc->mx.transform[1][1],pfc->mx.transform[1][0]),
|
|
(Fixed)pfc->pff->ui16EmHt
|
|
);
|
|
|
|
pfc->fxPtSize = fxPtSize(pfc);
|
|
}
|
|
|
|
if (!pfc->lD)
|
|
{
|
|
// this is win31 hack for emboldening: they always offset the bitmap to the
|
|
// right by one pixel and or it with the original bitmap. This of course only
|
|
// makes sense when writtinng left to right, when writing at 90 degrees, say,
|
|
// the bitmaps should be offsetted by one pixel up. In general, depending on
|
|
// the direction of the baseline, bitmap should be offset right, up, left or down,
|
|
|
|
if (pfc->flFontType & FO_SIM_BOLD)
|
|
cxMax += 1;
|
|
|
|
// we can liberally extend cxMax to the byte boundary, this is not
|
|
// going to change memory requirements of the system.
|
|
|
|
cxMax = ((cxMax + 7) & ~7);
|
|
pfc->cxMax = cxMax;
|
|
}
|
|
|
|
// now we have to determine how big in memory is the biggest glyph.
|
|
// let us remember that the rasterizer needs little more storage than the
|
|
// the engine does, because rasterizer will want dword aligned rows rather
|
|
// than byte aligned rows
|
|
|
|
{
|
|
DWORDLONG lrg;
|
|
|
|
// why am I dword instead byte extending cxMax? because that is
|
|
// how much rasterizer will want for this bitmap
|
|
|
|
ULONG cjMaxScan = ((cxMax + 31) & ~31) / 8;
|
|
lrg = UInt32x32To64(cjMaxScan, cyMax);
|
|
if (lrg > ULONG_MAX)
|
|
{
|
|
// the result does not fit in 32 bits, alloc memory will fail
|
|
// this is too big to digest, we fail to open fc
|
|
|
|
RETURN("TTFD! huge pt size, must fail\n", FALSE);
|
|
}
|
|
}
|
|
|
|
// We now have all the informaiton to set the gray bit
|
|
// appropriately.
|
|
|
|
vSetGrayState__FONTCONTEXT(pfc);
|
|
|
|
ASSERTDD(pfc->flFontType & FO_CHOSE_DEPTH,
|
|
"We haven't decided about pixel depth\n"
|
|
);
|
|
pfc->cjGlyphMax = CJGD(cxMax,cyMax,pfc);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// LONG iHipot(x, y)
|
|
//
|
|
// This routine returns the hypoteneous of a right triangle.
|
|
//
|
|
// FORMULA:
|
|
// use sq(x) + sq(y) = sq(hypo);
|
|
// start with MAX(x, y),
|
|
// use sq(x + 1) = sq(x) + 2x + 1 to incrementally get to the
|
|
// target hypotenouse.
|
|
//
|
|
// History:
|
|
// Mon 07-Feb-1994 -by- Bodin Dresevic [BodinD]
|
|
// update: update to use Fixed 16.16
|
|
// 10-Feb-1993 -by- Kent Settle (kentse)
|
|
// Stole from RASDD.
|
|
// 21-Aug-1991 -by- Lindsay Harris (lindsayh)
|
|
// Cleaned up UniDrive version, added comments etc.
|
|
//--------------------------------------------------------------------
|
|
|
|
STATIC ULONG iHipot(LONG x, LONG y)
|
|
{
|
|
ULONG hypo; /* Value to calculate */
|
|
ULONG delta; /* Used in the calculation loop */
|
|
ULONG target; /* Loop limit factor */
|
|
|
|
// quick exit for frequent trivial cases [bodind]
|
|
|
|
if (x < 0)
|
|
x = -x;
|
|
|
|
if (y < 0)
|
|
y = -y;
|
|
|
|
if (x == 0)
|
|
return y;
|
|
|
|
if (y == 0)
|
|
return x;
|
|
|
|
if (x > y)
|
|
{
|
|
hypo = x;
|
|
target = y * y;
|
|
}
|
|
else
|
|
{
|
|
hypo = y;
|
|
target = x * x;
|
|
}
|
|
|
|
for (delta = 0; delta < target; hypo++)
|
|
delta += ((hypo << 1) + 1);
|
|
|
|
return hypo;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bSingularXform
|
|
*
|
|
* Checks whether this is one of the xforms that the rasterizer is known
|
|
* to choke on. Those are the transforms that generate very
|
|
* narrow fonts (less than 0.5 pixels/em wide or tall). For fonts that
|
|
* allow only integer widths/em and heights/em this number will get rounded
|
|
* down to zero and generate divide by zero exception in the preprogram.
|
|
* We will flag such transforms as XFORM_SINGULAR and return empty bitmaps
|
|
* and outlines for them shortcircuiting the rasterizer which would die on
|
|
* us.
|
|
*
|
|
* Actually, for compatibility reasons we will have to change
|
|
* this plan a little bit. It turns out that
|
|
* win 31 does not allow for the rasterization of a font that is less
|
|
* than 2 pixels tall (ie. the Em Ht of the font in device space must be
|
|
* >= 2 pixels). If a request comes down to realize a font that is tall less
|
|
* than 2 pixels we will simply have to substitute the transform by a scaled
|
|
* transform that will produce a font of height two pixels. We will still keep
|
|
* our singular transform code in case a font is requested that is singular in
|
|
* X direction, that is, too narrow.
|
|
*
|
|
* History:
|
|
* 22-Sep-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
// smallest ppem allowed under win31:
|
|
|
|
#define WIN31_PPEM_CUTOFF 2
|
|
|
|
STATIC VOID vCheckForSingularXform (PFONTCONTEXT pfc) // OUT
|
|
{
|
|
|
|
register LONG lEmHtDev;
|
|
|
|
Fixed fxEmHtDev;
|
|
Fixed fxEmHtNot = LTOF16_16(pfc->pff->ui16EmHt);
|
|
Fixed fxScale;
|
|
Fixed fxEmWidthDev;
|
|
|
|
// xforms are conforming left multiplication rule v' = v * M i.e.:
|
|
//
|
|
// (x,0) -> x(m00,m01)
|
|
// (0,y) -> y(m10,m11)
|
|
//
|
|
// compute length of (0,Em) after it gets transformed to device space:
|
|
// We need to have fxEmHtDev computed with high precission, for we
|
|
// shall be using it to divide the original transform by.
|
|
// We want to avoid division by zero when that is not neccessary.
|
|
|
|
fxEmHtDev = FixMul(
|
|
iHipot(pfc->mx.transform[1][1],pfc->mx.transform[1][0]),
|
|
fxEmHtNot
|
|
);
|
|
|
|
lEmHtDev = F16_16TOLROUND(fxEmHtDev);
|
|
if (lEmHtDev < WIN31_PPEM_CUTOFF) // too small a transform:
|
|
{
|
|
pfc->flXform |= XFORM_2PPEM;
|
|
|
|
// according to win31 algorithm, we must scale this xform so that the
|
|
// resulting xform will produce font that is 2 pels tall.
|
|
// That is, the new transform M' is going to be
|
|
//
|
|
// M' = (WIN31_PPEM_CUTOFF / lEmHtDev) * M
|
|
//
|
|
// so that the following equation is satisfied:
|
|
//
|
|
// |(0,EmNotional) * M'| == WIN31_PPEM_CUTOFF == 2;
|
|
|
|
if (pfc->flXform & XFORM_HORIZ)
|
|
{
|
|
// in this special case the above formula for M' becomes:
|
|
//
|
|
// | m00/|m11| 0 |
|
|
// M' = (WIN31_PPEM_CUTOFF / EmNotional) * | |
|
|
// | 0 sgn(m11) |
|
|
|
|
#define LABS(x) ((x)<0)?(-x):(x)
|
|
|
|
Fixed fxAbsM11 = LABS(pfc->mx.transform[1][1]);
|
|
Fixed fxAbsM00 = LABS(pfc->mx.transform[0][0]);
|
|
|
|
LONG lSgn11 = (pfc->mx.transform[1][1] >= 0) ? 1 : -1;
|
|
LONG lSgn00 = (pfc->mx.transform[0][0] >= 0) ? 1 : -1;
|
|
|
|
fxScale = FixDiv(WIN31_PPEM_CUTOFF,pfc->pff->ui16EmHt);
|
|
|
|
pfc->mx.transform[1][1] = fxScale;
|
|
if (fxAbsM00 != fxAbsM11)
|
|
{
|
|
pfc->mx.transform[0][0] = LongMulDiv(fxScale,fxAbsM00,fxAbsM11);
|
|
}
|
|
else
|
|
{
|
|
pfc->mx.transform[0][0] = fxScale;
|
|
}
|
|
|
|
// fix the signs if needed:
|
|
|
|
if (lSgn11 < 0)
|
|
pfc->mx.transform[1][1] = - pfc->mx.transform[1][1];
|
|
|
|
if (lSgn00 < 0)
|
|
pfc->mx.transform[0][0] = - pfc->mx.transform[0][0];
|
|
}
|
|
else
|
|
{
|
|
// general case, compute scale (which involves division) once,
|
|
// and use it for all four members of the matrix:
|
|
|
|
fxScale = FixDiv(LTOF16_16(WIN31_PPEM_CUTOFF),fxEmHtDev);
|
|
|
|
pfc->mx.transform[0][0] = FixMul(pfc->mx.transform[0][0],fxScale);
|
|
pfc->mx.transform[0][1] = FixMul(pfc->mx.transform[0][1],fxScale);
|
|
pfc->mx.transform[1][0] = FixMul(pfc->mx.transform[1][0],fxScale);
|
|
pfc->mx.transform[1][1] = FixMul(pfc->mx.transform[1][1],fxScale);
|
|
|
|
// In general case must also fix the original EFLOAT xform because
|
|
// it is going to be used for computation of extents, max glyphs etc.
|
|
|
|
FFF(pfc->xfm.eM11, +pfc->mx.transform[0][0]);
|
|
FFF(pfc->xfm.eM22, +pfc->mx.transform[1][1]);
|
|
FFF(pfc->xfm.eM12, -pfc->mx.transform[0][1]);
|
|
FFF(pfc->xfm.eM21, -pfc->mx.transform[1][0]);
|
|
}
|
|
}
|
|
|
|
// Now check if the transform is singular in x. To do this
|
|
// compute length of (Em,0) after it gets transformed to device space:
|
|
|
|
fxEmWidthDev = FixMul(
|
|
iHipot(pfc->mx.transform[0][0],pfc->mx.transform[0][1]),
|
|
fxEmHtNot
|
|
);
|
|
|
|
if (fxEmWidthDev <= ONEHALFFIX)
|
|
{
|
|
// We are in trouble, we shall have to lie to the engine:
|
|
|
|
pfc->flXform |= XFORM_SINGULAR;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bNewXform:
|
|
*
|
|
* converts the transform matrix to the form the rasterizer likes
|
|
* and computes the global (per font) sizes that are relevant for this
|
|
* transform.
|
|
*
|
|
* History:
|
|
* 28-Mar-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
STATIC BOOL
|
|
bNewXform (
|
|
FONTOBJ *pfo,
|
|
PFONTCONTEXT pfc // OUT
|
|
)
|
|
{
|
|
// do not write immediately to pfc->mx until sure that all bFloatToL
|
|
// have succeeded. You do not want to leave this function and leave
|
|
// fc in a dirty state
|
|
|
|
BOOL bRet;
|
|
Fixed fx00, fx01, fx10, fx11;
|
|
|
|
// Get the transform elements.
|
|
|
|
XFORMOBJ_iGetXform(FONTOBJ_pxoGetXform(pfo), &pfc->xfm);
|
|
|
|
if (
|
|
!bFloatToL(pfc->xfm.eM11, &fx00) ||
|
|
!bFloatToL(pfc->xfm.eM22, &fx11) ||
|
|
!bFloatToL(pfc->xfm.eM12, &fx01) ||
|
|
!bFloatToL(pfc->xfm.eM21, &fx10)
|
|
)
|
|
RET_FALSE("TTFD!_bFloatToL failed\n");
|
|
|
|
// we are fine now, can not fail after this:
|
|
|
|
pfc->mx.transform[0][0] = fx00;
|
|
pfc->mx.transform[1][1] = fx11;
|
|
pfc->mx.transform[0][1] = -fx01;
|
|
pfc->mx.transform[1][0] = -fx10;
|
|
|
|
// components in the projective space are zero
|
|
|
|
pfc->mx.transform[2][2] = ONEFIX;
|
|
pfc->mx.transform[0][2] = (Fixed)0;
|
|
pfc->mx.transform[1][2] = (Fixed)0;
|
|
pfc->mx.transform[2][0] = (Fixed)0;
|
|
pfc->mx.transform[2][1] = (Fixed)0;
|
|
|
|
// set the flags for the transform:
|
|
|
|
pfc->flXform = 0;
|
|
|
|
if ((fx01 == 0) && (fx10 == 0))
|
|
pfc->flXform |= XFORM_HORIZ;
|
|
|
|
if ((fx00 == 0) && (fx11 == 0))
|
|
pfc->flXform |= XFORM_VERT;
|
|
|
|
// important to check for "singular transform"
|
|
// (ie. request for too small a font realization) after flags have been set
|
|
|
|
vCheckForSingularXform(pfc);
|
|
|
|
// no glyph metrics computation is valid yet
|
|
|
|
vInitGlyphState(&pfc->gstat);
|
|
|
|
// no memory to rasterize a glyph or produce glyph outline has been allocated
|
|
|
|
pfc->gstat.pv = NULL;
|
|
|
|
// now get the sizes for this transform
|
|
|
|
if (bRet = bComputeMaxGlyph(pfc))
|
|
{
|
|
// BEGIN Perpetua-Hack
|
|
if (pfc->pff->fl & FF_PERPETUA_REGULAR)
|
|
{
|
|
bRet = FALSE;
|
|
if (pfc->flXform & XFORM_POSITIVE_SCALE)
|
|
{
|
|
if (pfc->lEmHtDev <= PERPETUA_REGULAR_MAX_EM)
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
#if DBG
|
|
if (!bRet)
|
|
{
|
|
TTFD_PRINT(2,("Rejecting Perpetua Regular\n"));
|
|
}
|
|
#endif
|
|
}
|
|
// END Perpetua-Hack
|
|
}
|
|
return(bRet);
|
|
}
|
|
|
|
|
|
/******************************Public*Function*****************************\
|
|
* bFToL *
|
|
* *
|
|
* Convert an IEEE floating point number to a long integer. *
|
|
* *
|
|
* History: *
|
|
*
|
|
* Sun 17-Nov-1991 -by- Bodin Dresevic [BodinD]
|
|
* update:
|
|
*
|
|
* changed the line
|
|
* if (flType & CVT_TO_FIX) lExp += 4;
|
|
* to
|
|
* if (flType & CVT_TO_FIX) lExp += 16;
|
|
* to reflect that we are converting to 16.16 format rather than to 28.4
|
|
*
|
|
*
|
|
* 03-Jan-1991 -by- Wendy Wu [wendywu] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
STATIC BOOL bFloatToL(FLOAT e, PLONG pl)
|
|
{
|
|
|
|
LONG lEf, lExp;
|
|
|
|
lEf = (*((LONG *) &e)); // convert type EFLOAT to LONG
|
|
|
|
// if exponent < 0 then convert to 0 and return true
|
|
|
|
lExp = ((lEf >> 23) & 0xff) -127;
|
|
|
|
lExp += 16; // this is the only line I changed [bodind]
|
|
|
|
if (lExp < 0)
|
|
{
|
|
*pl = 0;
|
|
return(TRUE);
|
|
}
|
|
|
|
// if exponent <= 23 then
|
|
// lMantissa = (lEf & 0x7fffff) | 0x800000;
|
|
// if we are to truncate the fractions
|
|
// l = lMantissa >> (23 - lExponent);
|
|
// else
|
|
// l = ((lMantissa >> (23 - lExponent -1)) + 1) >> 1;
|
|
|
|
if (lExp <= 23)
|
|
{
|
|
*pl = (lEf & 0x80000000) ?
|
|
-(((((lEf & 0x7fffff) | 0x800000) >> (23 - lExp -1)) + 1) >> 1) :
|
|
((((lEf & 0x7fffff) | 0x800000) >> (23 - lExp -1)) + 1) >> 1;
|
|
return(TRUE);
|
|
}
|
|
|
|
// if exponent <= 30 then
|
|
// lMantissa = (lEf & 0x7fffff) | 0x800000;
|
|
// l = lMantissa << (lExponent - 23);
|
|
|
|
if (lExp <= 30)
|
|
{
|
|
*pl = (lEf & 0x80000000) ?
|
|
-(((lEf & 0x7fffff) | 0x800000) << (lExp - 23)) :
|
|
((lEf & 0x7fffff) | 0x800000) << (lExp - 23);
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* lFFF = long-float-from-fixed
|
|
*
|
|
* input: 16.16 representation
|
|
* output: LONG that is bit equivalent of the 32-bit ieee float
|
|
* equal to the fix point number. To recover the float
|
|
* the FLOAT representation you simply cast the bits as a float
|
|
* that is
|
|
*
|
|
* FLOAT e;
|
|
*
|
|
* *(LONG*)&e = lFFF(n16Dot16)
|
|
*
|
|
* History:
|
|
* Tue 03-Jan-1995 14:33:35 by Kirk Olynyk [kirko]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG lFFF(LONG l)
|
|
{
|
|
#if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
|
|
FLOAT e = ((FLOAT) l)/((FLOAT) 65536);
|
|
return(*(LONG*)&e);
|
|
#elif defined(_X86_)
|
|
int i; // shift count
|
|
unsigned k; // significand
|
|
|
|
if (k = (unsigned) l)
|
|
{
|
|
if (l < 0)
|
|
k = (unsigned) -l; // significand is positive, sign
|
|
// bit accounted for later
|
|
i = 0;
|
|
if (k < (1 << 16)) { // put the number in the
|
|
k <<= 16; // range 2^31 <= k < 2^32
|
|
i += 16; // by shifting to left, put
|
|
} // shift count in i
|
|
if (k < (1 << 24)) {
|
|
k <<= 8;
|
|
i += 8;
|
|
}
|
|
if (k < (1 << 28)) {
|
|
k <<= 4;
|
|
i += 4;
|
|
}
|
|
if (k < (1 << 30)) {
|
|
k <<= 2;
|
|
i += 2;
|
|
}
|
|
if (k < (1 << 31)) {
|
|
k <<= 1;
|
|
i += 1;
|
|
}
|
|
// at this point
|
|
// i = 31-floor(log2(abs(l)))
|
|
|
|
k += (1 << 7); // about to shift out
|
|
// the lowest 8-bits
|
|
// account for their effect by
|
|
// rounding. This has the effect
|
|
// that numbers are rounded away
|
|
// from zero as opposed to rounding
|
|
// stricktly up
|
|
k >>= 8; // shift out the lowest 8 bits
|
|
|
|
k &= ((1<<23) - 1); // 2^23 bit is implicit so mask it out
|
|
k |= (0xff & (142 - i)) << 23; // set exponent at correct place
|
|
if (l < 0) // if original number was negative
|
|
k |= (1<<31); // then set the sign bit
|
|
}
|
|
return((LONG) k);
|
|
#endif
|
|
}
|
|
|
|
|
|
#if DBG
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* VOID vFSError(FS_ENTRY iRet);
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* History:
|
|
* 25-Nov-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
VOID vFSError(FS_ENTRY iRet)
|
|
{
|
|
PCHAR psz;
|
|
|
|
switch (iRet)
|
|
{
|
|
case BAD_CALL_ERR:
|
|
psz = "BAD_CALL_ERR";
|
|
break;
|
|
case BAD_CLIENT_ID_ERR:
|
|
psz = "BAD_CLIENT_ID_ERR";
|
|
break;
|
|
case BAD_MAGIC_ERR:
|
|
psz = "BAD_MAGIC_ERR";
|
|
break;
|
|
case BAD_START_POINT_ERR:
|
|
psz = "BAD_START_POINT_ERR";
|
|
break;
|
|
case CLIENT_RETURNED_NULL:
|
|
psz = "CLIENT_RETURNED_NULL";
|
|
break;
|
|
case CONTOUR_DATA_ERR:
|
|
psz = "CONTOUR_DATA_ERR";
|
|
break;
|
|
case GLYPH_INDEX_ERR:
|
|
psz = "GLYPH_INDEX_ERR";
|
|
break;
|
|
case INSTRUCTION_SIZE_ERR:
|
|
psz = "INSTRUCTION_SIZE_ERR";
|
|
break;
|
|
case INVALID_GLYPH_INDEX:
|
|
psz = "INVALID_GLYPH_INDEX";
|
|
break;
|
|
case MISSING_SFNT_TABLE:
|
|
psz = "MISSING_SFNT_TABLE";
|
|
break;
|
|
case NULL_INPUT_PTR_ERR:
|
|
psz = "NULL_INPUT_PTR_ERR";
|
|
break;
|
|
case NULL_KEY_ERR:
|
|
psz = "NULL_KEY_ERR";
|
|
break;
|
|
case NULL_MEMORY_BASES_ERR:
|
|
psz = "NULL_MEMORY_BASES_ERR";
|
|
break;
|
|
case NULL_OUTPUT_PTR_ERR:
|
|
psz = "NULL_OUTPUT_PTR_ERR";
|
|
break;
|
|
case NULL_SFNT_DIR_ERR:
|
|
psz = "NULL_SFNT_DIR_ERR";
|
|
break;
|
|
case NULL_SFNT_FRAG_PTR_ERR:
|
|
psz = "NULL_SFNT_FRAG_PTR_ERR";
|
|
break;
|
|
case OUT_OFF_SEQUENCE_CALL_ERR:
|
|
psz = "OUT_OFF_SEQUENCE_CALL_ERR";
|
|
break;
|
|
case OUT_OF_RANGE_SUBTABLE:
|
|
psz = "OUT_OF_RANGE_SUBTABLE";
|
|
break;
|
|
case POINTS_DATA_ERR:
|
|
psz = "POINTS_DATA_ERR";
|
|
break;
|
|
case POINT_MIGRATION_ERR:
|
|
psz = "POINT_MIGRATION_ERR";
|
|
break;
|
|
case SCAN_ERR:
|
|
psz = "SCAN_ERR";
|
|
break;
|
|
case SFNT_DATA_ERR:
|
|
psz = "SFNT_DATA_ERR";
|
|
break;
|
|
case TRASHED_MEM_ERR:
|
|
psz = "TRASHED_MEM_ERR";
|
|
break;
|
|
case TRASHED_OUTLINE_CACHE:
|
|
psz = "TRASHED_OUTLINE_CACHE";
|
|
break;
|
|
case UNDEFINED_INSTRUCTION_ERR:
|
|
psz = "UNDEFINED_INSTRUCTION_ERR";
|
|
break;
|
|
case UNKNOWN_CMAP_FORMAT:
|
|
psz = "UNKNOWN_CMAP_FORMAT";
|
|
break;
|
|
case UNKNOWN_COMPOSITE_VERSION:
|
|
psz = "UNKNOWN_COMPOSITE_VERSION";
|
|
break;
|
|
case VOID_FUNC_PTR_BASE_ERR:
|
|
psz = "VOID_FUNC_PTR_BASE_ERR";
|
|
break;
|
|
case SBIT_COMPONENT_MISSING_ERR:
|
|
psz = "SBIT_COMPONENT_MISSING_ERR";
|
|
break;
|
|
default:
|
|
psz = "UNKNOWN FONT SCALER ERROR";
|
|
break;
|
|
|
|
}
|
|
TtfdDbgPrint ("\n Rasterizer Error: 0x%lx, %s \n", iRet, psz);
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* fxPtSize
|
|
*
|
|
* Effects: computes the size in points for this font realization
|
|
*
|
|
* History:
|
|
* 06-Aug-1992 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
STATIC LONG fxPtSize(PFONTCONTEXT pfc)
|
|
{
|
|
// This is done as follows:
|
|
//
|
|
// Transform
|
|
// (0, ui16EmHt) to device (pixel) space.
|
|
// Let us say that the vector obtained is (xEm, yEm).
|
|
// Then, ptSize should be computed as
|
|
// ptSize = 72 * sqrt((xEm/xRes)^2 + (yEm/yRes)^2);
|
|
|
|
// expanding here a bit we get:
|
|
// ptSize = 72 * ui16EmHt * sqrt((mx10/xRes)^2 + (mx11/yRes)^2);
|
|
|
|
Fixed x,y;
|
|
LONG lEmHtX72 = (LONG)(72 * pfc->pff->ui16EmHt);
|
|
|
|
// fxEmHtDev = FixMul(
|
|
// iHipot(pfc->mx.transform[1][1],pfc->mx.transform[1][0]),
|
|
// fxEmHtNot
|
|
// );
|
|
|
|
if (pfc->sizLogResPpi.cx == pfc->sizLogResPpi.cy)
|
|
{
|
|
return FixDiv(lEmHtX72, pfc->sizLogResPpi.cy);
|
|
}
|
|
else
|
|
{
|
|
x = LongMulDiv(lEmHtX72,pfc->mx.transform[1][0],pfc->sizLogResPpi.cx);
|
|
y = LongMulDiv(lEmHtX72,pfc->mx.transform[1][1],pfc->sizLogResPpi.cy);
|
|
return iHipot(x,y);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// this is win31 code intended as a comment for our code:
|
|
//
|
|
|
|
#ifdef THIS_IS_WIN31_CODE_INTENDED_AS_COMMENT
|
|
|
|
// Find out if a width Table is available
|
|
if (pfnt->ulHdmxPos && !(pfc->fStatus & FD_MORE_THAN_STRETCH) && pfc->Mx11 == pfc->Mx00)
|
|
{
|
|
unsigned i;
|
|
HDMXHEADER FAR *pHdmx;
|
|
HDMXTABLE FAR *pHdmxTable;
|
|
|
|
if (pHdmx = (HDMXHEADER FAR *) SfntReadFragment (pfc->fgi.clientID, pfnt->ulHdmxPos, pfnt->uHdmxSize))
|
|
{
|
|
if (pHdmx->Version == 0)
|
|
{
|
|
pHdmxTable = pHdmx->HdmxTable;
|
|
|
|
// Init the the glyph count
|
|
pfc->cHdmxRecord = (unsigned) SWAPL (pHdmx->cbSizeRecord);
|
|
|
|
// look through the table if the size is available
|
|
for (i = 0; i < (unsigned) SWAPW (pHdmx->cbRecord); i++, pHdmxTable = (HDMXTABLE FAR *)((char FAR *) pHdmxTable + pfc->cHdmxRecord))
|
|
if (pfc->Mx11 == (int) pHdmxTable->ucEmY)
|
|
{
|
|
pfc->ulHdmxPosTable = pfnt->ulHdmxPos + (i * pfc->cHdmxRecord + sizeof (HDMXHEADER));
|
|
break;
|
|
}
|
|
}
|
|
ReleaseSFNT (pHdmx);
|
|
}
|
|
}
|
|
|
|
#endif // THIS_IS_WIN31_CODE_INTENDED_AS_COMMENT
|
|
|
|
STATIC VOID vFindHdmxTable(PFONTCONTEXT pfc)
|
|
{
|
|
HDMXHEADER *phdr = (HDMXHEADER *)(
|
|
(pfc->ptp->ateOpt[IT_OPT_HDMX].dp) ?
|
|
((BYTE *)pfc->pff->pvView + pfc->ptp->ateOpt[IT_OPT_HDMX].dp) :
|
|
NULL
|
|
);
|
|
|
|
UINT cRecords;
|
|
ULONG cjRecord;
|
|
|
|
HDMXTABLE *phdmx, *phdmxEnd;
|
|
LONG yEmHt = pfc->lEmHtDev;
|
|
|
|
// assume failure, no hdmx table can be used:
|
|
|
|
pfc->phdmx = NULL;
|
|
|
|
// first see if hdmx table is there at all:
|
|
|
|
if (!phdr || !pfc->ptp->ateOpt[IT_OPT_HDMX].cj)
|
|
return;
|
|
|
|
// if table is there but not necessary since the whole font scales
|
|
// linearly at all sizes, we will ignore it:
|
|
|
|
//(phead->flags & SWAP(2))
|
|
// return;
|
|
|
|
// if transform is not such as to allow the use of hdmx table, return;
|
|
|
|
ASSERTDD(pfc->flXform & XFORM_POSITIVE_SCALE,
|
|
"vFindHdmxTable, bogus xform\n");
|
|
|
|
// if this is the version that we do not understand, return
|
|
|
|
if (phdr->Version != 0)
|
|
return;
|
|
|
|
cRecords = BE_UINT16(&phdr->cRecords);
|
|
cjRecord = (ULONG)SWAPL(phdr->cjRecord);
|
|
|
|
ASSERTDD((cjRecord & 3) == 0, "cjRecord\n");
|
|
|
|
// if yEmHt > 255, can not fit in the byte, so there is no need to
|
|
// to search for the hdmx entry:
|
|
|
|
if (yEmHt > 255)
|
|
return;
|
|
|
|
// Finally, find out if there is something useful there. Note that the
|
|
// table is sorted by size, so we can take an early out.
|
|
|
|
phdmx = (HDMXTABLE *)(phdr + 1);
|
|
phdmxEnd = (HDMXTABLE *)((PBYTE)phdmx + cRecords * cjRecord);
|
|
|
|
for
|
|
(
|
|
;
|
|
phdmx < phdmxEnd;
|
|
phdmx = (HDMXTABLE *)((PBYTE)phdmx + cjRecord)
|
|
)
|
|
{
|
|
if (((BYTE) yEmHt) <= phdmx->ucEmY)
|
|
{
|
|
if (((BYTE) yEmHt) == phdmx->ucEmY)
|
|
pfc->phdmx = phdmx; // We found it.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bGrabXform
|
|
*
|
|
* updates buffers 0 and 4, those that save the state of the transform.
|
|
* also for "buggy" fonts (URW FONTS) some of the transform dependent
|
|
* info (twightlight points) may be stored in the buffer 3, which otherwise would be shareable
|
|
* this is unfortunate, more memory is required
|
|
*
|
|
*
|
|
* History:
|
|
* 24-Mar-1993 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
BOOL
|
|
bGrabXform (
|
|
PFONTCONTEXT pfc
|
|
)
|
|
{
|
|
BOOL bOk = TRUE;
|
|
|
|
if (pfc->pff->pfcLast != pfc)
|
|
{
|
|
// have to refresh the transform, somebody has changed it on us
|
|
|
|
if (bOk = bSetXform(pfc))
|
|
{
|
|
// affirm that we are the ones who have set the transform last
|
|
|
|
pfc->pff->pfcLast = pfc;
|
|
}
|
|
else // make sure to restore the old current transform
|
|
{
|
|
#if DBG
|
|
BOOL bOkXform =
|
|
#endif
|
|
bSetXform(pfc->pff->pfcLast);
|
|
ASSERTDD(bOkXform, "bOkXform\n");
|
|
}
|
|
}
|
|
return (bOk);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vSetGrayState__FONTCONTEXT *
|
|
* *
|
|
* This routine set the FO_GRAY16 bit in pfc->flFontType and *
|
|
* pfc->pfo->flFontType as is appropriate. If the bit is set *
|
|
* then, later on, we shall make calls to the fs_FindGraySize and *
|
|
* fs_ContourGrayScan pair instead of the usual monochrome pair of *
|
|
* calls, fs_FindBitmapSize and fs_ContourScan. *
|
|
* *
|
|
* The only effect that this routine could have is to clear *
|
|
* the FO_GRAY16 flags in pfc->flFontType and pfc->pfo->flFontType. *
|
|
* *
|
|
* The only way in which this clearing could occur is if all of the *
|
|
* following conditions are met: 1) the caller has not set the *
|
|
* FO_NO_CHOICE bit; 2) the font has a 'gasp' table; 3) the 'gasp' *
|
|
* table indicates that for the requested number of pixels per em *
|
|
* the 'gasp' table indicates that the font should not be grayed; 4) *
|
|
* the glyphs of the font are not acted upon by a simple scaling *
|
|
* transformation. *
|
|
* *
|
|
* On Entry *
|
|
* *
|
|
* pfc->flFontType & FO_GRAY16 != 0 *
|
|
* pfc->pfo->flFontType & FO_GRAY16 != 0 *
|
|
* *
|
|
* Procedure *
|
|
* *
|
|
* 1. if the force bit is on then go to 6. *
|
|
* 2. if the transformation is not axial then go to 6. *
|
|
* 3. if the font does not gave a 'gasp' table then go to 6. *
|
|
* 4. if the gasp table says that this size is ok for graying then *
|
|
* go to 6. *
|
|
* 5. clear the FO_GRAY16 flags in both places *
|
|
* 6. return *
|
|
* *
|
|
* History: *
|
|
* Fri 10-Feb-1995 14:02:51 by Kirk Olynyk [kirko] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
VOID vSetGrayState__FONTCONTEXT(FONTCONTEXT *this)
|
|
{
|
|
#if DBG
|
|
void vPrintGASPTABLE(GASPTABLE*);
|
|
#endif
|
|
|
|
ptrdiff_t dp; // offset from the beginning of the font to the
|
|
// 'gasp' table
|
|
GASPTABLE *pgasp; // pointer to the 'gasp' table
|
|
USHORT usEmHt; // requested pixels per em
|
|
GASPRANGE *pgr, *pgrOut;
|
|
|
|
ASSERTDD(
|
|
this->flFontType == this->pfo->flFontType
|
|
,"flFontType value should be identical here\n"
|
|
);
|
|
ASSERTDD(
|
|
!(this->flFontType & FO_CHOSE_DEPTH)
|
|
,"We should not have chosen a level at this time\n"
|
|
);
|
|
|
|
this->flFontType |= FO_CHOSE_DEPTH;
|
|
if (this->flFontType & FO_GRAY16)
|
|
{
|
|
this->flFontType &= ~(FO_GRAY16);
|
|
if (this->flFontType & FO_NO_CHOICE)
|
|
{
|
|
this->flFontType |= FO_GRAY16;
|
|
}
|
|
else
|
|
{
|
|
if (!(dp = (ptrdiff_t) (this->ptp->ateOpt[IT_OPT_GASP].dp)))
|
|
{
|
|
USHORT fs;
|
|
|
|
// Win95 lifts the default GASP tables from the registry
|
|
// We should have the same behavior. Bug #11755
|
|
|
|
#define US2BE(x) ((((x) >> 8) | ((x) << 8)) & 0xFFFF)
|
|
static CONST USHORT gaspDefaultRegular[] = {
|
|
US2BE(0) // version
|
|
, US2BE(3) // numRanges
|
|
, US2BE(8) , US2BE(GASP_DOGRAY)
|
|
, US2BE(17) , US2BE(GASP_GRIDFIT)
|
|
, US2BE(USHRT_MAX) , US2BE(GASP_GRIDFIT + GASP_DOGRAY)
|
|
};
|
|
static CONST USHORT gaspDefaultBold[] = {
|
|
US2BE(0) // version
|
|
, US2BE(2) // numRanges
|
|
, US2BE(8) , US2BE(GASP_DOGRAY)
|
|
, US2BE(USHRT_MAX) , US2BE(GASP_GRIDFIT + GASP_DOGRAY)
|
|
};
|
|
static CONST USHORT *gaspDefaultItalic = gaspDefaultRegular;
|
|
|
|
#if DBG
|
|
if (gflTtfdDebug & DEBUG_GRAY)
|
|
{
|
|
TtfdDbgPrint("Supplying default GASPTABLE\n");
|
|
}
|
|
#endif // DBG
|
|
|
|
fs = this->pff->ifi.fsSelection;
|
|
if (fs & FM_SEL_ITALIC)
|
|
{
|
|
pgasp = (GASPTABLE*) gaspDefaultItalic;
|
|
}
|
|
else if (fs & FM_SEL_BOLD)
|
|
{
|
|
pgasp = (GASPTABLE*) gaspDefaultBold;
|
|
}
|
|
else
|
|
{
|
|
pgasp = (GASPTABLE*) gaspDefaultRegular;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pgasp = (GASPTABLE*) (((BYTE *)(this->pff->pvView)) + dp);
|
|
}
|
|
#if DBG
|
|
if (gflTtfdDebug & DEBUG_GRAY)
|
|
{
|
|
vPrintGASPTABLE(pgasp);
|
|
EngDebugBreak();
|
|
}
|
|
#endif
|
|
if (this->lEmHtDev > USHRT_MAX)
|
|
{
|
|
WARNING("vSetGrayScale: lEmHtDev > USHRT_MAX\n");
|
|
}
|
|
else
|
|
{
|
|
size_t cRanges;
|
|
int iLow, iHt, iHigh;
|
|
|
|
// Search the gasp table for the instructions
|
|
// for this particular em height. I have assumed that there
|
|
// are not too many GASP tables (typically 3 or less) so
|
|
// I use a linear search.
|
|
|
|
pgr = pgasp->gaspRange;
|
|
cRanges = BE_UINT16(&(pgasp->numRanges));
|
|
if (cRanges > 8)
|
|
{
|
|
WARNING("Unusual GASPTABLE : cRanges > 8\n");
|
|
cRanges = 8;
|
|
}
|
|
pgrOut = pgr + cRanges;
|
|
iLow = -1;
|
|
iHt = this->lEmHtDev;
|
|
for ( ; pgr < pgrOut; pgr++)
|
|
{
|
|
iHigh = (int) BE_UINT16(&(pgr->rangeMaxPPEM));
|
|
if (iLow < iHt && iHt <= iHigh)
|
|
{
|
|
if (GASP_DOGRAY & BE_UINT16(&(pgr->rangeGaspBehavior)))
|
|
{
|
|
this->flFontType |= FO_GRAY16;
|
|
}
|
|
break;
|
|
}
|
|
iLow = iHigh;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this->flFontType & FO_GRAY16)
|
|
{
|
|
#if DBG
|
|
if (gflTtfdDebug & DEBUG_GRAY)
|
|
{
|
|
TtfdDbgPrint("Choosing 16-Level Glyphs\n");
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
if (gflTtfdDebug & DEBUG_GRAY)
|
|
{
|
|
TtfdDbgPrint(
|
|
"\n"
|
|
"We came into the routine with the FO_GRAY16 bit set.\n"
|
|
"However, for some reason it is not possible to has\n"
|
|
"anti-aliased the text. Therefore we must adjust the\n"
|
|
"font context and inform it that that antialiasing \n"
|
|
"is out of the picture. We will continue and create\n"
|
|
"a monochrome font.\n"
|
|
);
|
|
}
|
|
#endif
|
|
this->flFontType |= FO_NOGRAY16;
|
|
this->pfo->flFontType = this->flFontType;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
/******************************Public*Routine******************************\
|
|
* *
|
|
* Routine Name: *
|
|
* *
|
|
* vPrintGASPTABLE *
|
|
* *
|
|
* Routine Description: *
|
|
* *
|
|
* Dumps a GASPTABLE to the debug screen *
|
|
* *
|
|
* Arguments: *
|
|
* *
|
|
* pgasp -- pointer to a big endian GASPTABLE *
|
|
* *
|
|
* Return Value: *
|
|
* *
|
|
* none *
|
|
* *
|
|
\**************************************************************************/
|
|
|
|
void vPrintGASPTABLE(GASPTABLE *pgasp)
|
|
{
|
|
GASPRANGE *pgr, *pgrOut;
|
|
|
|
TtfdDbgPrint(
|
|
"\n"
|
|
"-------------------------------------\n"
|
|
"GASPTABLE HEADER\n"
|
|
"-------------------------------------\n"
|
|
"pgasp = %-#x\n"
|
|
"version = %d\n"
|
|
"numRanges = %d\n"
|
|
"-------------------------------------\n"
|
|
" rangeMaxPPEM rangeGaspBehavior\n"
|
|
"-------------------------------------\n"
|
|
, pgasp
|
|
, BE_UINT16(&(pgasp->version))
|
|
, BE_UINT16(&(pgasp->numRanges))
|
|
);
|
|
pgr = pgasp->gaspRange;
|
|
pgrOut = pgr + BE_UINT16(&(pgasp->numRanges));
|
|
for (pgr = pgasp->gaspRange; pgr < pgrOut; pgr++)
|
|
{
|
|
char *psz;
|
|
USHORT us = BE_UINT16(&(pgr->rangeGaspBehavior));
|
|
us &= (GASP_GRIDFIT | GASP_DOGRAY);
|
|
switch (us)
|
|
{
|
|
case 0:
|
|
psz = "";
|
|
break;
|
|
case GASP_GRIDFIT:
|
|
psz = "GASP_GRIDFIT";
|
|
break;
|
|
case GASP_DOGRAY:
|
|
psz = "GASP_DOGRAY";
|
|
break;
|
|
case GASP_GRIDFIT | GASP_DOGRAY:
|
|
psz = "GASP_GRIDFIT | GASP_DOGRAY";
|
|
break;
|
|
}
|
|
TtfdDbgPrint(
|
|
" %12d %s\n"
|
|
, BE_UINT16(&(pgr->rangeMaxPPEM))
|
|
, psz
|
|
);
|
|
}
|
|
TtfdDbgPrint(
|
|
"-------------------------------------\n\n\n"
|
|
);
|
|
}
|
|
#endif
|